Compare commits
24 Commits
v1.2.3+for
...
v1.2.3+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac39f119e2 | ||
|
|
016faf3df0 | ||
|
|
b2d6879282 | ||
|
|
89afc05d5c | ||
|
|
ee20ee0722 | ||
|
|
02f9f8c8ea | ||
|
|
de3a252884 | ||
|
|
5e7a00de3e | ||
|
|
2858aeb55e | ||
|
|
357104efa9 | ||
|
|
bb8027c7ef | ||
|
|
f9dd787009 | ||
|
|
e005731ba6 | ||
|
|
18ae3f4f61 | ||
|
|
10dfe0327e | ||
|
|
1d1e921137 | ||
|
|
0985a4c968 | ||
|
|
8df589c103 | ||
|
|
71b6b2f451 | ||
|
|
d85940ded8 | ||
|
|
e9e491c0b0 | ||
|
|
c73562fb75 | ||
|
|
3feacb59c8 | ||
|
|
a033d711c1 |
@@ -62,7 +62,8 @@
|
|||||||
<data android:scheme="megalodon-android-auth" android:host="callback"/>
|
<data android:scheme="megalodon-android-auth" android:host="callback"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">
|
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize"
|
||||||
|
android:theme="@style/TransparentDialog">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND"/>
|
<action android:name="android.intent.action.SEND"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.joinmastodon.android;
|
|||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -12,6 +11,7 @@ import android.widget.Toast;
|
|||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.ComposeFragment;
|
import org.joinmastodon.android.fragments.ComposeFragment;
|
||||||
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.jsoup.internal.StringUtil;
|
import org.jsoup.internal.StringUtil;
|
||||||
|
|
||||||
@@ -28,18 +28,34 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
|||||||
UiUtils.setUserPreferredTheme(this);
|
UiUtils.setUserPreferredTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
|
|
||||||
|
String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
boolean isMastodonURL = UiUtils.looksLikeMastodonUrl(text);
|
||||||
|
|
||||||
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
||||||
if(sessions.isEmpty()){
|
if(sessions.isEmpty()){
|
||||||
Toast.makeText(this, R.string.err_not_logged_in, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.err_not_logged_in, Toast.LENGTH_SHORT).show();
|
||||||
finish();
|
finish();
|
||||||
}else if(sessions.size()==1){
|
}else if(sessions.size()==1 && !isMastodonURL){
|
||||||
openComposeFragment(sessions.get(0).getID());
|
openComposeFragment(sessions.get(0).getID());
|
||||||
}else{
|
}else{
|
||||||
getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
|
new AccountSwitcherSheet(this, null, true, isMastodonURL, (accountId, open) -> {
|
||||||
UiUtils.pickAccount(this, null, R.string.choose_account, 0,
|
if (open) {
|
||||||
session -> openComposeFragment(session.getID()),
|
UiUtils.lookupURL(this, accountId, text, false, (clazz, args) -> {
|
||||||
b -> b.setOnCancelListener(d -> finish())
|
if (clazz == null) {
|
||||||
);
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args.putString("fromExternalShare", clazz.getSimpleName());
|
||||||
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
intent.putExtras(args);
|
||||||
|
finish();
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
openComposeFragment(accountId);
|
||||||
|
}
|
||||||
|
}).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -20,12 +21,15 @@ import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
|||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
|
|
||||||
public class MainActivity extends FragmentStackActivity{
|
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
|
||||||
|
private Fragment currentFragment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState){
|
protected void onCreate(@Nullable Bundle savedInstanceState){
|
||||||
UiUtils.setUserPreferredTheme(this);
|
UiUtils.setUserPreferredTheme(this);
|
||||||
@@ -35,10 +39,18 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
|
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
|
||||||
showFragmentClearingBackStack(new CustomWelcomeFragment());
|
showFragmentClearingBackStack(new CustomWelcomeFragment());
|
||||||
}else{
|
}else{
|
||||||
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
|
|
||||||
AccountSession session;
|
AccountSession session;
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
Intent intent=getIntent();
|
Intent intent=getIntent();
|
||||||
|
if(intent.hasExtra("fromExternalShare")) {
|
||||||
|
AccountSessionManager.getInstance()
|
||||||
|
.setLastActiveAccountID(intent.getStringExtra("account"));
|
||||||
|
AccountSessionManager.getInstance().maybeUpdateLocalInfo(
|
||||||
|
AccountSessionManager.getInstance().getLastActiveAccount());
|
||||||
|
showFragmentForExternalShare(intent.getExtras());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
|
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
|
||||||
boolean hasNotification = intent.hasExtra("notification");
|
boolean hasNotification = intent.hasExtra("notification");
|
||||||
if(fromNotification){
|
if(fromNotification){
|
||||||
@@ -52,6 +64,7 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
}else{
|
}else{
|
||||||
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
}
|
}
|
||||||
|
AccountSessionManager.getInstance().maybeUpdateLocalInfo(session);
|
||||||
args.putString("account", session.getID());
|
args.putString("account", session.getID());
|
||||||
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
|
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
@@ -75,11 +88,12 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent){
|
protected void onNewIntent(Intent intent){
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
if(intent.getBooleanExtra("fromNotification", false)){
|
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
|
||||||
|
if (intent.hasExtra("fromExternalShare")) showFragmentForExternalShare(intent.getExtras());
|
||||||
|
else if (intent.getBooleanExtra("fromNotification", false)) {
|
||||||
String accountID=intent.getStringExtra("accountID");
|
String accountID=intent.getStringExtra("accountID");
|
||||||
AccountSession accountSession;
|
|
||||||
try{
|
try{
|
||||||
accountSession=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
}catch(IllegalStateException x){
|
}catch(IllegalStateException x){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -124,6 +138,19 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
showFragment(fragment);
|
showFragment(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showFragmentForExternalShare(Bundle args) {
|
||||||
|
String clazz = args.getString("fromExternalShare");
|
||||||
|
Fragment fragment = switch (clazz) {
|
||||||
|
case "ThreadFragment" -> new ThreadFragment();
|
||||||
|
case "ProfileFragment" -> new ProfileFragment();
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
if (fragment == null) return;
|
||||||
|
args.putBoolean("_can_go_back", true);
|
||||||
|
fragment.setArguments(args);
|
||||||
|
showFragment(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
private void showCompose(){
|
private void showCompose(){
|
||||||
AccountSession session=AccountSessionManager.getInstance().getLastActiveAccount();
|
AccountSession session=AccountSessionManager.getInstance().getLastActiveAccount();
|
||||||
if(session==null || !session.activated)
|
if(session==null || !session.activated)
|
||||||
@@ -153,18 +180,35 @@ public class MainActivity extends FragmentStackActivity{
|
|||||||
(fragmentContainers.get(fragmentContainers.size() - 1)).getId()
|
(fragmentContainers.get(fragmentContainers.size() - 1)).getId()
|
||||||
);
|
);
|
||||||
Bundle currentArgs = currentFragment.getArguments();
|
Bundle currentArgs = currentFragment.getArguments();
|
||||||
if (this.fragmentContainers.size() == 1
|
if (fragmentContainers.size() != 1
|
||||||
&& currentArgs != null
|
|| currentArgs == null
|
||||||
&& currentArgs.getBoolean("_can_go_back", false)
|
|| !currentArgs.getBoolean("_can_go_back", false)) {
|
||||||
&& currentArgs.containsKey("account")) {
|
super.onBackPressed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currentArgs.getBoolean("_finish_on_back", false)) {
|
||||||
|
finish();
|
||||||
|
} else if (currentArgs.containsKey("account")) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString("account", currentArgs.getString("account"));
|
args.putString("account", currentArgs.getString("account"));
|
||||||
args.putString("tab", "notifications");
|
if (getIntent().getBooleanExtra("fromNotification", false)) {
|
||||||
|
args.putString("tab", "notifications");
|
||||||
|
}
|
||||||
Fragment fragment=new HomeFragment();
|
Fragment fragment=new HomeFragment();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
showFragmentClearingBackStack(fragment);
|
showFragmentClearingBackStack(fragment);
|
||||||
} else {
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFragment(Fragment fragment) {
|
||||||
|
super.showFragment(fragment);
|
||||||
|
this.currentFragment = fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
super.onProvideAssistContent(assistContent);
|
||||||
|
callFragmentToProvideAssistContent(currentFragment, assistContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.joinmastodon.android.api.session.AccountSession;
|
|||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Mention;
|
||||||
import org.joinmastodon.android.model.NotificationAction;
|
import org.joinmastodon.android.model.NotificationAction;
|
||||||
import org.joinmastodon.android.model.Preferences;
|
import org.joinmastodon.android.model.Preferences;
|
||||||
import org.joinmastodon.android.model.PushNotification;
|
import org.joinmastodon.android.model.PushNotification;
|
||||||
@@ -33,6 +34,7 @@ import org.joinmastodon.android.model.StatusPrivacy;
|
|||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -273,8 +275,23 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
}
|
}
|
||||||
CharSequence input = remoteInput.getCharSequence(ACTION_KEY_TEXT_REPLY);
|
CharSequence input = remoteInput.getCharSequence(ACTION_KEY_TEXT_REPLY);
|
||||||
|
|
||||||
|
// copied from ComposeFragment - TODO: generalize?
|
||||||
|
ArrayList<String> mentions=new ArrayList<>();
|
||||||
|
Status status = notification.status;
|
||||||
|
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
||||||
|
if(!status.account.id.equals(ownID))
|
||||||
|
mentions.add('@'+status.account.acct);
|
||||||
|
for(Mention mention:status.mentions){
|
||||||
|
if(mention.id.equals(ownID))
|
||||||
|
continue;
|
||||||
|
String m='@'+mention.acct;
|
||||||
|
if(!mentions.contains(m))
|
||||||
|
mentions.add(m);
|
||||||
|
}
|
||||||
|
String initialText=mentions.isEmpty() ? "" : TextUtils.join(" ", mentions)+" ";
|
||||||
|
|
||||||
CreateStatus.Request req=new CreateStatus.Request();
|
CreateStatus.Request req=new CreateStatus.Request();
|
||||||
req.status = input.toString();
|
req.status = initialText + input.toString();
|
||||||
req.language = preferences.postingDefaultLanguage;
|
req.language = preferences.postingDefaultLanguage;
|
||||||
req.visibility = preferences.postingDefaultVisibility;
|
req.visibility = preferences.postingDefaultVisibility;
|
||||||
req.inReplyToId = notification.status.id;
|
req.inReplyToId = notification.status.id;
|
||||||
@@ -282,7 +299,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
req.spoilerText = "re: " + notification.status.spoilerText;
|
req.spoilerText = "re: " + notification.status.spoilerText;
|
||||||
}
|
}
|
||||||
|
|
||||||
new CreateStatus(req, UUID.randomUUID().toString()).setCallback(new Callback<Status>() {
|
new CreateStatus(req, UUID.randomUUID().toString()).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Status status) {
|
public void onSuccess(Status status) {
|
||||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.joinmastodon.android.api.session;
|
package org.joinmastodon.android.api.session;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.CacheController;
|
import org.joinmastodon.android.api.CacheController;
|
||||||
import org.joinmastodon.android.api.MastodonAPIController;
|
import org.joinmastodon.android.api.MastodonAPIController;
|
||||||
import org.joinmastodon.android.api.PushSubscriptionManager;
|
import org.joinmastodon.android.api.PushSubscriptionManager;
|
||||||
@@ -15,6 +17,7 @@ import org.joinmastodon.android.model.Token;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class AccountSession{
|
public class AccountSession{
|
||||||
public Token token;
|
public Token token;
|
||||||
@@ -89,7 +92,14 @@ public class AccountSession{
|
|||||||
return pushSubscriptionManager;
|
return pushSubscriptionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instance getInstance() {
|
public Optional<Instance> getInstance() {
|
||||||
return AccountSessionManager.getInstance().getInstanceInfo(domain);
|
return Optional.ofNullable(AccountSessionManager.getInstance().getInstanceInfo(domain));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri getInstanceUri() {
|
||||||
|
return new Uri.Builder()
|
||||||
|
.scheme("https")
|
||||||
|
.authority(domain)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,14 +125,16 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void writeAccountsFile(){
|
public synchronized void writeAccountsFile(){
|
||||||
File file=new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
File tmpFile = new File(MastodonApp.context.getFilesDir(), "accounts.json~");
|
||||||
|
File file = new File(MastodonApp.context.getFilesDir(), "accounts.json");
|
||||||
try{
|
try{
|
||||||
try(FileOutputStream out=new FileOutputStream(file)){
|
try(FileOutputStream out=new FileOutputStream(tmpFile)){
|
||||||
SessionsStorageWrapper w=new SessionsStorageWrapper();
|
SessionsStorageWrapper w=new SessionsStorageWrapper();
|
||||||
w.accounts=new ArrayList<>(sessions.values());
|
w.accounts=new ArrayList<>(sessions.values());
|
||||||
OutputStreamWriter writer=new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
OutputStreamWriter writer=new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
||||||
MastodonAPIController.gson.toJson(w, writer);
|
MastodonAPIController.gson.toJson(w, writer);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
if (!tmpFile.renameTo(file)) Log.e(TAG, "Error renaming " + tmpFile.getPath() + " to " + file.getPath());
|
||||||
}
|
}
|
||||||
}catch(IOException x){
|
}catch(IOException x){
|
||||||
Log.e(TAG, "Error writing accounts file", x);
|
Log.e(TAG, "Error writing accounts file", x);
|
||||||
@@ -256,31 +258,35 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void maybeUpdateLocalInfo(){
|
public void maybeUpdateLocalInfo(){
|
||||||
|
maybeUpdateLocalInfo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void maybeUpdateLocalInfo(AccountSession activeSession){
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
HashSet<String> domains=new HashSet<>();
|
HashSet<String> domains=new HashSet<>();
|
||||||
for(AccountSession session:sessions.values()){
|
for(AccountSession session:sessions.values()){
|
||||||
domains.add(session.domain.toLowerCase());
|
domains.add(session.domain.toLowerCase());
|
||||||
// if(now-session.infoLastUpdated>24L*3600_000L){
|
if(now-session.infoLastUpdated>24L*3600_000L || session == activeSession){
|
||||||
updateSessionPreferences(session);
|
updateSessionPreferences(session);
|
||||||
updateSessionLocalInfo(session);
|
updateSessionLocalInfo(session);
|
||||||
// }
|
}
|
||||||
// if(now-session.filtersLastUpdated>3600_000L){
|
if(now-session.filtersLastUpdated>3600_000L || session == activeSession){
|
||||||
updateSessionWordFilters(session);
|
updateSessionWordFilters(session);
|
||||||
// }
|
}
|
||||||
updateSessionMarkers(session);
|
updateSessionMarkers(session);
|
||||||
}
|
}
|
||||||
if(loadedInstances){
|
if(loadedInstances){
|
||||||
maybeUpdateCustomEmojis(domains);
|
maybeUpdateCustomEmojis(domains, activeSession != null ? activeSession.domain : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeUpdateCustomEmojis(Set<String> domains){
|
private void maybeUpdateCustomEmojis(Set<String> domains, String activeDomain){
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
for(String domain:domains){
|
for(String domain:domains){
|
||||||
// Long lastUpdated=instancesLastUpdated.get(domain);
|
Long lastUpdated=instancesLastUpdated.get(domain);
|
||||||
// if(lastUpdated==null || now-lastUpdated>24L*3600_000L){
|
if(lastUpdated==null || now-lastUpdated>24L*3600_000L || domain.equals(activeDomain)){
|
||||||
updateInstanceInfo(domain);
|
updateInstanceInfo(domain);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +414,9 @@ public class AccountSessionManager{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error){
|
public void onError(ErrorResponse error){
|
||||||
|
InstanceInfoStorageWrapper wrapper=new InstanceInfoStorageWrapper();
|
||||||
|
wrapper.instance = instance;
|
||||||
|
MastodonAPIController.runInBackground(()->writeInstanceInfoFile(wrapper, domain));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.execNoAuth(domain);
|
.execNoAuth(domain);
|
||||||
@@ -419,10 +427,13 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeInstanceInfoFile(InstanceInfoStorageWrapper emojis, String domain){
|
private void writeInstanceInfoFile(InstanceInfoStorageWrapper emojis, String domain){
|
||||||
try(FileOutputStream out=new FileOutputStream(getInstanceInfoFile(domain))){
|
File file = getInstanceInfoFile(domain);
|
||||||
|
File tmpFile = new File(file.getPath() + "~");
|
||||||
|
try(FileOutputStream out=new FileOutputStream(tmpFile)){
|
||||||
OutputStreamWriter writer=new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
OutputStreamWriter writer=new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
||||||
MastodonAPIController.gson.toJson(emojis, writer);
|
MastodonAPIController.gson.toJson(emojis, writer);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
if (!tmpFile.renameTo(file)) Log.e(TAG, "Error renaming " + tmpFile.getPath() + " to " + file.getPath());
|
||||||
}catch(IOException x){
|
}catch(IOException x){
|
||||||
Log.w(TAG, "Error writing instance info file for "+domain, x);
|
Log.w(TAG, "Error writing instance info file for "+domain, x);
|
||||||
}
|
}
|
||||||
@@ -442,7 +453,7 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
if(!loadedInstances){
|
if(!loadedInstances){
|
||||||
loadedInstances=true;
|
loadedInstances=true;
|
||||||
maybeUpdateCustomEmojis(domains);
|
maybeUpdateCustomEmojis(domains, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,12 +474,7 @@ public class AccountSessionManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Instance getInstanceInfo(String domain){
|
public Instance getInstanceInfo(String domain){
|
||||||
Instance instance = instances.get(domain);
|
return instances.get(domain);
|
||||||
if (instance == null) {
|
|
||||||
throw new IllegalStateException("Cannot get instance for " + domain + ". Sessions: "
|
|
||||||
+ String.join(", ", instances.keySet()));
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAccountInfo(String id, Account account){
|
public void updateAccountInfo(String id, Account account){
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -130,4 +131,13 @@ public class AccountTimelineFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.ACCOUNT;
|
return Filter.FilterContext.ACCOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
// could return different uris based on filter (e.g. media -> "/media"), but i want to
|
||||||
|
// return the remote url to the user, and i don't know whether i'd need to append
|
||||||
|
// '#media' (akkoma/pleroma) or '/media' (glitch/mastodon) since i don't know anything
|
||||||
|
// about the remote instance. so, just returning the base url to the user instead
|
||||||
|
return Uri.parse(user.url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.joinmastodon.android.fragments;
|
|||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -103,4 +104,9 @@ public class AnnouncementsFragment extends BaseStatusListFragment<Announcement>
|
|||||||
})
|
})
|
||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? base.path("/announcements").build() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@@ -25,6 +26,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
|
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||||
@@ -45,6 +47,7 @@ import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
|||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||||
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.joinmastodon.android.utils.TypedObjectPool;
|
import org.joinmastodon.android.utils.TypedObjectPool;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -68,7 +71,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends RecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop, HasFab{
|
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends RecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop, HasFab, ProvidesAssistContent.ProvidesWebUri {
|
||||||
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
||||||
protected DisplayItemsAdapter adapter;
|
protected DisplayItemsAdapter adapter;
|
||||||
protected String accountID;
|
protected String accountID;
|
||||||
@@ -570,6 +573,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
warning.getItem().status.filterRevealed = true;
|
warning.getItem().status.filterRevealed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getAccountID(){
|
public String getAccountID(){
|
||||||
return accountID;
|
return accountID;
|
||||||
}
|
}
|
||||||
@@ -703,6 +707,10 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return attachmentViewsPool;
|
return attachmentViewsPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
assistContent.setWebUri(getWebUri(getSession().getInstanceUri().buildUpon()));
|
||||||
|
}
|
||||||
|
|
||||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
|
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
|
||||||
@@ -41,4 +42,9 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.ACCOUNT;
|
return Filter.FilterContext.ACCOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path("/bookmarks").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,9 +263,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
Nav.finish(this);
|
Nav.finish(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(customEmojis.isEmpty()){
|
|
||||||
AccountSessionManager.getInstance().updateInstanceInfo(instanceDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bundle bundle = savedInstanceState != null ? savedInstanceState : getArguments();
|
Bundle bundle = savedInstanceState != null ? savedInstanceState : getArguments();
|
||||||
if (bundle.containsKey("scheduledStatus")) scheduledStatus=Parcels.unwrap(bundle.getParcelable("scheduledStatus"));
|
if (bundle.containsKey("scheduledStatus")) scheduledStatus=Parcels.unwrap(bundle.getParcelable("scheduledStatus"));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
|
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
|
||||||
@@ -41,4 +42,11 @@ public class FavoritedStatusListFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.ACCOUNT;
|
return Filter.FilterContext.ACCOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.encodedPath(isInstanceAkkoma()
|
||||||
|
? '/' + getSession().self.username + "#favorites"
|
||||||
|
: "/favourites").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -24,6 +25,7 @@ import org.joinmastodon.android.ui.text.HtmlParser;
|
|||||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -46,7 +48,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class FollowRequestsListFragment extends RecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop{
|
public class FollowRequestsListFragment extends RecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||||
private GetAccountRelationships relationshipsRequest;
|
private GetAccountRelationships relationshipsRequest;
|
||||||
@@ -148,6 +150,16 @@ public class FollowRequestsListFragment extends RecyclerFragment<FollowRequestsL
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path(isInstanceAkkoma() ? "/friend-requests" : "/follow_requests").build();
|
||||||
|
}
|
||||||
|
|
||||||
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
public AccountsAdapter(){
|
public AccountsAdapter(){
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -14,14 +15,15 @@ import org.joinmastodon.android.model.Hashtag;
|
|||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop {
|
public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private String nextMaxID;
|
private String nextMaxID;
|
||||||
private String accountId;
|
private String accountID;
|
||||||
|
|
||||||
public FollowedHashtagsFragment() {
|
public FollowedHashtagsFragment() {
|
||||||
super(20);
|
super(20);
|
||||||
@@ -31,7 +33,7 @@ public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implemen
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Bundle args=getArguments();
|
Bundle args=getArguments();
|
||||||
accountId=args.getString("account");
|
accountID=args.getString("account");
|
||||||
setTitle(R.string.sk_hashtags_you_follow);
|
setTitle(R.string.sk_hashtags_you_follow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +64,7 @@ public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implemen
|
|||||||
onDataLoaded(result, nextMaxID!=null);
|
onDataLoaded(result, nextMaxID!=null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.exec(accountId);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,6 +77,16 @@ public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implemen
|
|||||||
smoothScrollRecyclerViewToTop(list);
|
smoothScrollRecyclerViewToTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/followed_tags").build();
|
||||||
|
}
|
||||||
|
|
||||||
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -109,7 +121,7 @@ public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implemen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick() {
|
public void onClick() {
|
||||||
UiUtils.openHashtagTimeline(getActivity(), accountId, item.name, item.following);
|
UiUtils.openHashtagTimeline(getActivity(), accountID, item.name, item.following);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface HasAccountID {
|
||||||
|
String getAccountID();
|
||||||
|
|
||||||
|
default AccountSession getSession() {
|
||||||
|
return AccountSessionManager.getInstance().getAccount(getAccountID());
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isInstanceAkkoma() {
|
||||||
|
return getInstance().map(Instance::isPleroma).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Optional<Instance> getInstance() {
|
||||||
|
return getSession().getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -8,7 +9,6 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
@@ -159,4 +159,9 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.PUBLIC;
|
return Filter.FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path((isInstanceAkkoma() ? "/tag/" : "/tags") + hashtag).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android.fragments;
|
|||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -16,6 +17,11 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.IdRes;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
||||||
@@ -30,16 +36,13 @@ import org.joinmastodon.android.model.Notification;
|
|||||||
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.TabBar;
|
import org.joinmastodon.android.ui.views.TabBar;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import androidx.annotation.IdRes;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
|
||||||
|
|
||||||
import me.grishka.appkit.FragmentStackActivity;
|
import me.grishka.appkit.FragmentStackActivity;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
@@ -52,7 +55,7 @@ import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||||
|
|
||||||
public class HomeFragment extends AppKitFragment implements OnBackPressedListener{
|
public class HomeFragment extends AppKitFragment implements OnBackPressedListener, ProvidesAssistContent, HasAccountID {
|
||||||
private FragmentRootLinearLayout content;
|
private FragmentRootLinearLayout content;
|
||||||
private HomeTabFragment homeTabFragment;
|
private HomeTabFragment homeTabFragment;
|
||||||
private NotificationsFragment notificationsFragment;
|
private NotificationsFragment notificationsFragment;
|
||||||
@@ -74,8 +77,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
E.register(this);
|
E.register(this);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
setTitle(R.string.sk_app_name);
|
setTitle(R.string.sk_app_name);
|
||||||
Instance instance = AccountSessionManager.getInstance().getAccount(accountID).getInstance();
|
isPleroma = AccountSessionManager.getInstance().getAccount(accountID).getInstance()
|
||||||
isPleroma = instance.isPleroma();
|
.map(Instance::isPleroma)
|
||||||
|
.orElse(false);
|
||||||
|
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
@@ -222,6 +226,13 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCurrentTab(@IdRes int tab){
|
||||||
|
if(tab==currentTab)
|
||||||
|
return;
|
||||||
|
tabBar.selectTab(tab);
|
||||||
|
onTabSelected(tab);
|
||||||
|
}
|
||||||
|
|
||||||
private void onTabSelected(@IdRes int tab){
|
private void onTabSelected(@IdRes int tab){
|
||||||
Fragment newFragment=fragmentForTab(tab);
|
Fragment newFragment=fragmentForTab(tab);
|
||||||
if(tab==currentTab){
|
if(tab==currentTab){
|
||||||
@@ -263,7 +274,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
|
||||||
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
|
options.add(session.self.displayName+"\n("+session.self.username+"@"+session.domain+")");
|
||||||
}
|
}
|
||||||
new AccountSwitcherSheet(getActivity()).show();
|
new AccountSwitcherSheet(getActivity(), this).show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -296,10 +307,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
|
|
||||||
public void updateNotificationBadge() {
|
public void updateNotificationBadge() {
|
||||||
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
Instance instance = session.getInstance();
|
Optional<Instance> instance = session.getInstance();
|
||||||
if (instance == null) return;
|
if (instance.isEmpty()) return; // avoiding incompatibility with akkoma
|
||||||
|
|
||||||
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance != null && instance.isPleroma())
|
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance.get().isPleroma())
|
||||||
.setCallback(new Callback<>() {
|
.setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Notification> notifications) {
|
public void onSuccess(List<Notification> notifications) {
|
||||||
@@ -336,4 +347,14 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
public void onAllNotificationsSeen(AllNotificationsSeenEvent allNotificationsSeenEvent) {
|
public void onAllNotificationsSeen(AllNotificationsSeenEvent allNotificationsSeenEvent) {
|
||||||
setNotificationBadge(false);
|
setNotificationBadge(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
callFragmentToProvideAssistContent(fragmentForTab(currentTab), assistContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.FragmentTransaction;
|
import android.app.FragmentTransaction;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -54,6 +55,7 @@ import org.joinmastodon.android.model.TimelineDefinition;
|
|||||||
import org.joinmastodon.android.ui.SimpleViewHolder;
|
import org.joinmastodon.android.ui.SimpleViewHolder;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -71,7 +73,7 @@ import me.grishka.appkit.fragments.OnBackPressedListener;
|
|||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener, HasFab {
|
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener, HasFab, ProvidesAssistContent {
|
||||||
private static final int ANNOUNCEMENTS_RESULT = 654;
|
private static final int ANNOUNCEMENTS_RESULT = 654;
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
@@ -693,6 +695,11 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
return fab;
|
return fab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
callFragmentToProvideAssistContent(fragments[pager.getCurrentItem()], assistContent);
|
||||||
|
}
|
||||||
|
|
||||||
private class HomePagerAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
|
private class HomePagerAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -285,4 +286,9 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.HOME;
|
return Filter.FilterContext.HOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path("/").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -168,4 +168,9 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.HOME;
|
return Filter.FilterContext.HOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path("/lists/" + listID).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,258 +0,0 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import org.joinmastodon.android.api.requests.lists.AddAccountsToList;
|
|
||||||
import org.joinmastodon.android.api.requests.lists.CreateList;
|
|
||||||
import org.joinmastodon.android.api.requests.lists.GetLists;
|
|
||||||
import org.joinmastodon.android.api.requests.lists.RemoveAccountsFromList;
|
|
||||||
import org.joinmastodon.android.events.ListDeletedEvent;
|
|
||||||
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
|
|
||||||
import org.joinmastodon.android.model.ListTimeline;
|
|
||||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
|
||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
|
||||||
import org.joinmastodon.android.ui.views.ListTimelineEditor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
|
||||||
import me.grishka.appkit.api.Callback;
|
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
|
||||||
|
|
||||||
public class ListTimelinesFragment extends RecyclerFragment<ListTimeline> implements ScrollableToTop {
|
|
||||||
private String accountId;
|
|
||||||
private String profileAccountId;
|
|
||||||
private final HashMap<String, Boolean> userInListBefore = new HashMap<>();
|
|
||||||
private final HashMap<String, Boolean> userInList = new HashMap<>();
|
|
||||||
private ListsAdapter adapter;
|
|
||||||
|
|
||||||
public ListTimelinesFragment() {
|
|
||||||
super(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
Bundle args=getArguments();
|
|
||||||
accountId=args.getString("account");
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
E.register(this);
|
|
||||||
|
|
||||||
if(args.containsKey("profileAccount")){
|
|
||||||
profileAccountId=args.getString("profileAccount");
|
|
||||||
String profileDisplayUsername = args.getString("profileDisplayUsername");
|
|
||||||
setTitle(getString(R.string.sk_lists_with_user, profileDisplayUsername));
|
|
||||||
} else {
|
|
||||||
setTitle(R.string.sk_your_lists);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onShown(){
|
|
||||||
super.onShown();
|
|
||||||
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 0.5f, 56, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
|
||||||
inflater.inflate(R.menu.menu_list, menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
if (item.getItemId() == R.id.create) {
|
|
||||||
ListTimelineEditor editor = new ListTimelineEditor(getContext());
|
|
||||||
new M3AlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(R.string.sk_create_list_title)
|
|
||||||
.setIcon(R.drawable.ic_fluent_people_add_28_regular)
|
|
||||||
.setView(editor)
|
|
||||||
.setPositiveButton(R.string.sk_create, (d, which) ->
|
|
||||||
new CreateList(editor.getTitle(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(ListTimeline list) {
|
|
||||||
data.add(0, list);
|
|
||||||
adapter.notifyItemRangeInserted(0, 1);
|
|
||||||
E.post(new ListUpdatedCreatedEvent(list.id, list.title, list.repliesPolicy));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error) {
|
|
||||||
error.showToast(getContext());
|
|
||||||
}
|
|
||||||
}).exec(accountId)
|
|
||||||
)
|
|
||||||
.setNegativeButton(R.string.cancel, (d, which) -> {})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveListMembership(String listId, boolean isMember) {
|
|
||||||
userInList.put(listId, isMember);
|
|
||||||
List<String> accountIdList = Collections.singletonList(profileAccountId);
|
|
||||||
MastodonAPIRequest<Object> req = isMember ? new AddAccountsToList(listId, accountIdList) : new RemoveAccountsFromList(listId, accountIdList);
|
|
||||||
req.setCallback(new Callback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Object o) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse error) {
|
|
||||||
error.showToast(getContext());
|
|
||||||
}
|
|
||||||
}).exec(accountId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doLoadData(int offset, int count){
|
|
||||||
userInListBefore.clear();
|
|
||||||
userInList.clear();
|
|
||||||
currentRequest=(profileAccountId != null ? new GetLists(profileAccountId) : new GetLists())
|
|
||||||
.setCallback(new SimpleCallback<>(this) {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(List<ListTimeline> lists) {
|
|
||||||
if (getActivity() == null) return;
|
|
||||||
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
|
|
||||||
userInList.putAll(userInListBefore);
|
|
||||||
if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false);
|
|
||||||
if (profileAccountId == null) return;
|
|
||||||
|
|
||||||
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListTimelinesFragment.this) {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(List<ListTimeline> allLists) {
|
|
||||||
if (getActivity() == null) return;
|
|
||||||
List<ListTimeline> newLists = new ArrayList<>();
|
|
||||||
for (ListTimeline l : allLists) {
|
|
||||||
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
|
|
||||||
if (!userInListBefore.containsKey(l.id)) {
|
|
||||||
userInListBefore.put(l.id, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
userInList.putAll(userInListBefore);
|
|
||||||
onDataLoaded(newLists, false);
|
|
||||||
}
|
|
||||||
}).exec(accountId);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.exec(accountId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onListDeletedEvent(ListDeletedEvent event) {
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
|
||||||
ListTimeline item = data.get(i);
|
|
||||||
if (item.id.equals(event.id)) {
|
|
||||||
data.remove(i);
|
|
||||||
adapter.notifyItemRemoved(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onListUpdatedCreatedEvent(ListUpdatedCreatedEvent event) {
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
|
||||||
ListTimeline item = data.get(i);
|
|
||||||
if (item.id.equals(event.id)) {
|
|
||||||
item.title = event.title;
|
|
||||||
item.repliesPolicy = event.repliesPolicy;
|
|
||||||
adapter.notifyItemChanged(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RecyclerView.Adapter<ListViewHolder> getAdapter() {
|
|
||||||
return adapter = new ListsAdapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scrollToTop() {
|
|
||||||
smoothScrollRecyclerViewToTop(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ListsAdapter extends RecyclerView.Adapter<ListViewHolder>{
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
|
||||||
return new ListViewHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ListViewHolder holder, int position) {
|
|
||||||
holder.bind(data.get(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return data.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ListViewHolder extends BindableViewHolder<ListTimeline> implements UsableRecyclerView.Clickable{
|
|
||||||
private final TextView title;
|
|
||||||
private final CheckBox listToggle;
|
|
||||||
|
|
||||||
public ListViewHolder(){
|
|
||||||
super(getActivity(), R.layout.item_text, list);
|
|
||||||
title=findViewById(R.id.title);
|
|
||||||
listToggle=findViewById(R.id.list_toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBind(ListTimeline item) {
|
|
||||||
title.setText(item.title);
|
|
||||||
title.setCompoundDrawablesRelativeWithIntrinsicBounds(itemView.getContext().getDrawable(R.drawable.ic_fluent_people_24_regular), null, null, null);
|
|
||||||
if (profileAccountId != null) {
|
|
||||||
Boolean checked = userInList.get(item.id);
|
|
||||||
listToggle.setVisibility(View.VISIBLE);
|
|
||||||
listToggle.setChecked(userInList.containsKey(item.id) && checked != null && checked);
|
|
||||||
listToggle.setOnClickListener(this::onClickToggle);
|
|
||||||
} else {
|
|
||||||
listToggle.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onClickToggle(View view) {
|
|
||||||
saveListMembership(item.id, listToggle.isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick() {
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", accountId);
|
|
||||||
args.putString("listID", item.id);
|
|
||||||
args.putString("listTitle", item.title);
|
|
||||||
if (item.repliesPolicy != null) args.putInt("repliesPolicy", item.repliesPolicy.ordinal());
|
|
||||||
Nav.go(getActivity(), ListTimelineFragment.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.E;
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.api.requests.lists.AddAccountsToList;
|
||||||
|
import org.joinmastodon.android.api.requests.lists.CreateList;
|
||||||
|
import org.joinmastodon.android.api.requests.lists.GetLists;
|
||||||
|
import org.joinmastodon.android.api.requests.lists.RemoveAccountsFromList;
|
||||||
|
import org.joinmastodon.android.events.ListDeletedEvent;
|
||||||
|
import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
|
||||||
|
import org.joinmastodon.android.model.ListTimeline;
|
||||||
|
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||||
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
|
import org.joinmastodon.android.ui.views.ListTimelineEditor;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.grishka.appkit.Nav;
|
||||||
|
import me.grishka.appkit.api.Callback;
|
||||||
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
|
public class ListsFragment extends RecyclerFragment<ListTimeline> implements ScrollableToTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
|
private String accountID;
|
||||||
|
private String profileAccountId;
|
||||||
|
private final HashMap<String, Boolean> userInListBefore = new HashMap<>();
|
||||||
|
private final HashMap<String, Boolean> userInList = new HashMap<>();
|
||||||
|
private ListsAdapter adapter;
|
||||||
|
|
||||||
|
public ListsFragment() {
|
||||||
|
super(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
Bundle args = getArguments();
|
||||||
|
accountID = args.getString("account");
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
E.register(this);
|
||||||
|
|
||||||
|
if(args.containsKey("profileAccount")){
|
||||||
|
profileAccountId=args.getString("profileAccount");
|
||||||
|
String profileDisplayUsername = args.getString("profileDisplayUsername");
|
||||||
|
setTitle(getString(R.string.sk_lists_with_user, profileDisplayUsername));
|
||||||
|
} else {
|
||||||
|
setTitle(R.string.sk_your_lists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onShown(){
|
||||||
|
super.onShown();
|
||||||
|
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 0.5f, 56, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.menu_list, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.create) {
|
||||||
|
ListTimelineEditor editor = new ListTimelineEditor(getContext());
|
||||||
|
new M3AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.sk_create_list_title)
|
||||||
|
.setIcon(R.drawable.ic_fluent_people_add_28_regular)
|
||||||
|
.setView(editor)
|
||||||
|
.setPositiveButton(R.string.sk_create, (d, which) ->
|
||||||
|
new CreateList(editor.getTitle(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ListTimeline list) {
|
||||||
|
data.add(0, list);
|
||||||
|
adapter.notifyItemRangeInserted(0, 1);
|
||||||
|
E.post(new ListUpdatedCreatedEvent(list.id, list.title, list.repliesPolicy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(getContext());
|
||||||
|
}
|
||||||
|
}).exec(accountID)
|
||||||
|
)
|
||||||
|
.setNegativeButton(R.string.cancel, (d, which) -> {})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveListMembership(String listId, boolean isMember) {
|
||||||
|
userInList.put(listId, isMember);
|
||||||
|
List<String> accountIdList = Collections.singletonList(profileAccountId);
|
||||||
|
MastodonAPIRequest<Object> req = isMember ? new AddAccountsToList(listId, accountIdList) : new RemoveAccountsFromList(listId, accountIdList);
|
||||||
|
req.setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object o) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(getContext());
|
||||||
|
}
|
||||||
|
}).exec(accountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doLoadData(int offset, int count){
|
||||||
|
userInListBefore.clear();
|
||||||
|
userInList.clear();
|
||||||
|
currentRequest=(profileAccountId != null ? new GetLists(profileAccountId) : new GetLists())
|
||||||
|
.setCallback(new SimpleCallback<>(this) {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<ListTimeline> lists) {
|
||||||
|
if (getActivity() == null) return;
|
||||||
|
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
|
||||||
|
userInList.putAll(userInListBefore);
|
||||||
|
if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false);
|
||||||
|
if (profileAccountId == null) return;
|
||||||
|
|
||||||
|
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListsFragment.this) {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<ListTimeline> allLists) {
|
||||||
|
if (getActivity() == null) return;
|
||||||
|
List<ListTimeline> newLists = new ArrayList<>();
|
||||||
|
for (ListTimeline l : allLists) {
|
||||||
|
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
|
||||||
|
if (!userInListBefore.containsKey(l.id)) {
|
||||||
|
userInListBefore.put(l.id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userInList.putAll(userInListBefore);
|
||||||
|
onDataLoaded(newLists, false);
|
||||||
|
}
|
||||||
|
}).exec(accountID);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(accountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onListDeletedEvent(ListDeletedEvent event) {
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
ListTimeline item = data.get(i);
|
||||||
|
if (item.id.equals(event.id)) {
|
||||||
|
data.remove(i);
|
||||||
|
adapter.notifyItemRemoved(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onListUpdatedCreatedEvent(ListUpdatedCreatedEvent event) {
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
ListTimeline item = data.get(i);
|
||||||
|
if (item.id.equals(event.id)) {
|
||||||
|
item.title = event.title;
|
||||||
|
item.repliesPolicy = event.repliesPolicy;
|
||||||
|
adapter.notifyItemChanged(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RecyclerView.Adapter<ListViewHolder> getAdapter() {
|
||||||
|
return adapter = new ListsAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scrollToTop() {
|
||||||
|
smoothScrollRecyclerViewToTop(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path("/lists").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListsAdapter extends RecyclerView.Adapter<ListViewHolder>{
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||||
|
return new ListViewHolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ListViewHolder holder, int position) {
|
||||||
|
holder.bind(data.get(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ListViewHolder extends BindableViewHolder<ListTimeline> implements UsableRecyclerView.Clickable{
|
||||||
|
private final TextView title;
|
||||||
|
private final CheckBox listToggle;
|
||||||
|
|
||||||
|
public ListViewHolder(){
|
||||||
|
super(getActivity(), R.layout.item_text, list);
|
||||||
|
title=findViewById(R.id.title);
|
||||||
|
listToggle=findViewById(R.id.list_toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBind(ListTimeline item) {
|
||||||
|
title.setText(item.title);
|
||||||
|
title.setCompoundDrawablesRelativeWithIntrinsicBounds(itemView.getContext().getDrawable(R.drawable.ic_fluent_people_24_regular), null, null, null);
|
||||||
|
if (profileAccountId != null) {
|
||||||
|
Boolean checked = userInList.get(item.id);
|
||||||
|
listToggle.setVisibility(View.VISIBLE);
|
||||||
|
listToggle.setChecked(userInList.containsKey(item.id) && checked != null && checked);
|
||||||
|
listToggle.setOnClickListener(this::onClickToggle);
|
||||||
|
} else {
|
||||||
|
listToggle.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClickToggle(View view) {
|
||||||
|
saveListMembership(item.id, listToggle.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick() {
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", accountID);
|
||||||
|
args.putString("listID", item.id);
|
||||||
|
args.putString("listTitle", item.title);
|
||||||
|
if (item.repliesPolicy != null) args.putInt("repliesPolicy", item.repliesPolicy.ordinal());
|
||||||
|
Nav.go(getActivity(), ListTimelineFragment.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android.fragments;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -13,6 +14,12 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -24,12 +31,7 @@ import org.joinmastodon.android.ui.SimpleViewHolder;
|
|||||||
import org.joinmastodon.android.ui.tabs.TabLayout;
|
import org.joinmastodon.android.ui.tabs.TabLayout;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
|
||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
@@ -37,7 +39,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class NotificationsFragment extends MastodonToolbarFragment implements ScrollableToTop{
|
public class NotificationsFragment extends MastodonToolbarFragment implements ScrollableToTop, ProvidesAssistContent {
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
@@ -47,7 +49,6 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
private NotificationsListFragment allNotificationsFragment, mentionsFragment;
|
private NotificationsListFragment allNotificationsFragment, mentionsFragment;
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -227,6 +228,11 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
callFragmentToProvideAssistContent(getFragmentForPage(pager.getCurrentItem()), assistContent);
|
||||||
|
}
|
||||||
|
|
||||||
private class DiscoverPagerAdapter extends RecyclerView.Adapter<SimpleViewHolder>{
|
private class DiscoverPagerAdapter extends RecyclerView.Adapter<SimpleViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -9,10 +10,8 @@ import com.squareup.otto.Subscribe;
|
|||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
|
||||||
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
||||||
import org.joinmastodon.android.api.requests.notifications.PleromaMarkNotificationsRead;
|
import org.joinmastodon.android.api.requests.notifications.PleromaMarkNotificationsRead;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
||||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||||
@@ -22,6 +21,7 @@ import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
|||||||
import org.joinmastodon.android.model.Emoji;
|
import org.joinmastodon.android.model.Emoji;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Instance;
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.Markers;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
||||||
@@ -44,7 +44,6 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
||||||
@@ -156,15 +155,15 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
loadRelationships(needRelationships);
|
loadRelationships(needRelationships);
|
||||||
maxID=result.maxID;
|
maxID=result.maxID;
|
||||||
|
|
||||||
if(offset==0 && !result.items.isEmpty() && !result.isFromCache() && AccountSessionManager.getInstance().getAccount(accountID).markers.notifications != null){
|
Markers markers = AccountSessionManager.getInstance().getAccount(accountID).markers;
|
||||||
|
if(offset==0 && !result.items.isEmpty() && !result.isFromCache() && markers != null && markers.notifications != null){
|
||||||
E.post(new AllNotificationsSeenEvent());
|
E.post(new AllNotificationsSeenEvent());
|
||||||
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
|
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
|
||||||
if (AccountSessionManager.getInstance().getAccount(accountID).markers != null)
|
AccountSessionManager.getInstance().getAccount(accountID).markers
|
||||||
AccountSessionManager.getInstance().getAccount(accountID).markers
|
.notifications.lastReadId = result.items.get(0).id;
|
||||||
.notifications.lastReadId = result.items.get(0).id;
|
|
||||||
AccountSessionManager.getInstance().writeAccountsFile();
|
AccountSessionManager.getInstance().writeAccountsFile();
|
||||||
|
|
||||||
if (AccountSessionManager.getInstance().getAccount(accountID).getInstance().isPleroma())
|
if (AccountSessionManager.getInstance().getAccount(accountID).getInstance().map(Instance::isPleroma).orElse(false))
|
||||||
new PleromaMarkNotificationsRead(result.items.get(0).id).exec(accountID);
|
new PleromaMarkNotificationsRead(result.items.get(0).id).exec(accountID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,4 +271,11 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
displayItems.subList(index, lastIndex).clear();
|
displayItems.subList(index, lastIndex).clear();
|
||||||
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path(isInstanceAkkoma()
|
||||||
|
? "/users/" + getSession().self.username + "/interactions"
|
||||||
|
: "/notifications").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.animation.AnimatorSet;
|
|||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -50,7 +51,6 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||||
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
|
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
|
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
|
||||||
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
|
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
|
||||||
@@ -75,6 +75,7 @@ import org.joinmastodon.android.ui.views.CoverImageView;
|
|||||||
import org.joinmastodon.android.ui.views.LinkedTextView;
|
import org.joinmastodon.android.ui.views.LinkedTextView;
|
||||||
import org.joinmastodon.android.ui.views.NestedRecyclerScrollView;
|
import org.joinmastodon.android.ui.views.NestedRecyclerScrollView;
|
||||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -92,6 +93,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
@@ -111,7 +113,7 @@ import me.grishka.appkit.utils.CubicBezierInterpolator;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class ProfileFragment extends LoaderFragment implements OnBackPressedListener, ScrollableToTop, HasFab{
|
public class ProfileFragment extends LoaderFragment implements OnBackPressedListener, ScrollableToTop, HasFab, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private static final int AVATAR_RESULT=722;
|
private static final int AVATAR_RESULT=722;
|
||||||
private static final int COVER_RESULT=343;
|
private static final int COVER_RESULT=343;
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
loadRelationship();
|
loadRelationship();
|
||||||
else {
|
else {
|
||||||
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(domain);
|
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(domain);
|
||||||
if (instance.isPleroma()) {
|
if (instance != null && instance.isPleroma()) {
|
||||||
maxFields = instance.pleroma.metadata.fieldsLimits.maxFields;
|
maxFields = instance.pleroma.metadata.fieldsLimits.maxFields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -712,7 +714,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
args.putString("profileAccount", profileAccountID);
|
args.putString("profileAccount", profileAccountID);
|
||||||
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
||||||
}
|
}
|
||||||
Nav.go(getActivity(), ListTimelinesFragment.class, args);
|
Nav.go(getActivity(), ListsFragment.class, args);
|
||||||
}else if(id==R.id.followed_hashtags){
|
}else if(id==R.id.followed_hashtags){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
@@ -1168,6 +1170,21 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
if (adapter != null) adapter.notifyDataSetChanged();
|
if (adapter != null) adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
callFragmentToProvideAssistContent(getFragmentForPage(pager.getCurrentItem()), assistContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return Uri.parse(account.url);
|
||||||
|
}
|
||||||
|
|
||||||
private class MetadataAdapter extends UsableRecyclerView.Adapter<BaseViewHolder> implements ImageLoaderRecyclerAdapter {
|
private class MetadataAdapter extends UsableRecyclerView.Adapter<BaseViewHolder> implements ImageLoaderRecyclerAdapter {
|
||||||
public MetadataAdapter(){
|
public MetadataAdapter(){
|
||||||
super(imgLoader);
|
super(imgLoader);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
@@ -181,4 +182,10 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
// TODO: adapt when frontends finally implement a scheduled posts list
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import android.content.Intent;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
@@ -59,9 +59,11 @@ import org.joinmastodon.android.ui.OutlineProviders;
|
|||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.TextInputFrameLayout;
|
import org.joinmastodon.android.ui.views.TextInputFrameLayout;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
@@ -78,7 +80,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class SettingsFragment extends MastodonToolbarFragment{
|
public class SettingsFragment extends MastodonToolbarFragment implements ProvidesAssistContent.ProvidesWebUri {
|
||||||
private UsableRecyclerView list;
|
private UsableRecyclerView list;
|
||||||
private ArrayList<Item> items=new ArrayList<>();
|
private ArrayList<Item> items=new ArrayList<>();
|
||||||
private ThemeItem themeItem;
|
private ThemeItem themeItem;
|
||||||
@@ -105,7 +107,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
imageCache = ImageCache.getInstance(getActivity());
|
imageCache = ImageCache.getInstance(getActivity());
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
Instance instance = session.getInstance();
|
Optional<Instance> instance = session.getInstance();
|
||||||
String instanceName = UiUtils.getInstanceName(accountID);
|
String instanceName = UiUtils.getInstanceName(accountID);
|
||||||
|
|
||||||
if(GithubSelfUpdater.needSelfUpdating()){
|
if(GithubSelfUpdater.needSelfUpdating()){
|
||||||
@@ -223,7 +225,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.showReplies=i.checked;
|
GlobalUserPreferences.showReplies=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
if (instance.isPleroma()) {
|
if (instance.map(Instance::isPleroma).orElse(false)) {
|
||||||
items.add(new ButtonItem(R.string.sk_settings_reply_visibility, R.drawable.ic_fluent_chat_24_regular, b->{
|
items.add(new ButtonItem(R.string.sk_settings_reply_visibility, R.drawable.ic_fluent_chat_24_regular, b->{
|
||||||
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
||||||
popupMenu.inflate(R.menu.reply_visibility);
|
popupMenu.inflate(R.menu.reply_visibility);
|
||||||
@@ -299,7 +301,9 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
needAppRestart=true;
|
||||||
}));
|
}));
|
||||||
boolean translationAvailable = instance.v2 != null && instance.v2.configuration.translation != null && instance.v2.configuration.translation.enabled;
|
boolean translationAvailable = instance
|
||||||
|
.map(i -> i.v2 != null && i.v2.configuration.translation != null && i.v2.configuration.translation.enabled)
|
||||||
|
.orElse(false);
|
||||||
items.add(new SmallTextItem(getString(translationAvailable ?
|
items.add(new SmallTextItem(getString(translationAvailable ?
|
||||||
R.string.sk_settings_translation_availability_note_available :
|
R.string.sk_settings_translation_availability_note_available :
|
||||||
R.string.sk_settings_translation_availability_note_unavailable, instanceName)));
|
R.string.sk_settings_translation_availability_note_unavailable, instanceName)));
|
||||||
@@ -324,16 +328,18 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
items.add(new TextItem(R.string.sk_settings_auth, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/auth/edit"), R.drawable.ic_fluent_open_24_regular));
|
items.add(new TextItem(R.string.sk_settings_auth, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/auth/edit"), R.drawable.ic_fluent_open_24_regular));
|
||||||
|
|
||||||
items.add(new HeaderItem(instanceName));
|
items.add(new HeaderItem(instanceName));
|
||||||
items.add(new TextItem(R.string.sk_settings_rules, ()->{
|
items.add(new TextItem(R.string.sk_settings_rules, instance.<Runnable>map(i -> () -> {
|
||||||
Bundle args=new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putParcelable("instance", Parcels.wrap(instance));
|
args.putParcelable("instance", Parcels.wrap(i));
|
||||||
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
Nav.go(getActivity(), InstanceRulesFragment.class, args);
|
||||||
}, R.drawable.ic_fluent_task_list_ltr_24_regular));
|
}).orElse(null), R.drawable.ic_fluent_task_list_ltr_24_regular));
|
||||||
items.add(new TextItem(R.string.sk_settings_about_instance , ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/about"), R.drawable.ic_fluent_info_24_regular));
|
items.add(new TextItem(R.string.sk_settings_about_instance , ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/about"), R.drawable.ic_fluent_info_24_regular));
|
||||||
items.add(new TextItem(R.string.settings_tos, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular));
|
items.add(new TextItem(R.string.settings_tos, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular));
|
||||||
items.add(new TextItem(R.string.settings_privacy_policy, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular));
|
items.add(new TextItem(R.string.settings_privacy_policy, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular));
|
||||||
items.add(new TextItem(R.string.log_out, this::confirmLogOut, R.drawable.ic_fluent_sign_out_24_regular));
|
items.add(new TextItem(R.string.log_out, this::confirmLogOut, R.drawable.ic_fluent_sign_out_24_regular));
|
||||||
if (!TextUtils.isEmpty(instance.version)) items.add(new SmallTextItem(getString(R.string.sk_settings_server_version, instance.version)));
|
items.add(new SmallTextItem(instance
|
||||||
|
.map(i -> getString(R.string.sk_settings_server_version, i.version))
|
||||||
|
.orElse(getString(R.string.sk_instance_info_unavailable))));
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.sk_instance_features));
|
items.add(new HeaderItem(R.string.sk_instance_features));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_content_types, 0, GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID), (i)->{
|
items.add(new SwitchItem(R.string.sk_settings_content_types, 0, GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID), (i)->{
|
||||||
@@ -361,14 +367,16 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
b.setText(getContentTypeString(contentType));
|
b.setText(getContentTypeString(contentType));
|
||||||
contentTypeMenu = popupMenu.getMenu();
|
contentTypeMenu = popupMenu.getMenu();
|
||||||
contentTypeMenu.findItem(ContentType.getContentTypeRes(contentType)).setChecked(true);
|
contentTypeMenu.findItem(ContentType.getContentTypeRes(contentType)).setChecked(true);
|
||||||
ContentType.adaptMenuToInstance(contentTypeMenu, instance);
|
instance.ifPresent(i -> ContentType.adaptMenuToInstance(contentTypeMenu, i));
|
||||||
}));
|
}));
|
||||||
items.add(new SmallTextItem(getString(R.string.sk_settings_default_content_type_explanation)));
|
items.add(new SmallTextItem(getString(R.string.sk_settings_default_content_type_explanation)));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_support_local_only, 0, GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID), i->{
|
items.add(new SwitchItem(R.string.sk_settings_support_local_only, 0, GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID), i->{
|
||||||
glitchModeItem.enabled = i.checked;
|
glitchModeItem.enabled = i.checked;
|
||||||
if (i.checked) {
|
if (i.checked) {
|
||||||
GlobalUserPreferences.accountsWithLocalOnlySupport.add(accountID);
|
GlobalUserPreferences.accountsWithLocalOnlySupport.add(accountID);
|
||||||
if (instance.pleroma == null) GlobalUserPreferences.accountsInGlitchMode.add(accountID);
|
if (!instance.map(Instance::isPleroma).orElse(false)) {
|
||||||
|
GlobalUserPreferences.accountsInGlitchMode.add(accountID);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GlobalUserPreferences.accountsWithLocalOnlySupport.remove(accountID);
|
GlobalUserPreferences.accountsWithLocalOnlySupport.remove(accountID);
|
||||||
GlobalUserPreferences.accountsInGlitchMode.remove(accountID);
|
GlobalUserPreferences.accountsInGlitchMode.remove(accountID);
|
||||||
@@ -734,6 +742,16 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/settings").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
private static abstract class Item{
|
private static abstract class Item{
|
||||||
public abstract int getViewType();
|
public abstract int getViewType();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -24,13 +25,13 @@ import java.util.stream.Collectors;
|
|||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
public class StatusEditHistoryFragment extends StatusListFragment{
|
public class StatusEditHistoryFragment extends StatusListFragment{
|
||||||
private String id;
|
private String id, url;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
id=getArguments().getString("id");
|
id=getArguments().getString("id");
|
||||||
|
url=getArguments().getString("url");
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,4 +163,9 @@ public class StatusEditHistoryFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return Uri.parse(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ import java.util.stream.Stream;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
|
|
||||||
public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
public abstract class StatusListFragment extends BaseStatusListFragment<Status> {
|
||||||
protected EventListener eventListener=new EventListener();
|
protected EventListener eventListener=new EventListener();
|
||||||
|
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||||
@@ -182,7 +183,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig){
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
if (getParentFragment() instanceof HomeTabFragment home) home.updateToolbarLogo();
|
if (getParentFragment() instanceof HomeTabFragment home) home.updateToolbarLogo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
|||||||
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
public class ThreadFragment extends StatusListFragment{
|
public class ThreadFragment extends StatusListFragment implements ProvidesAssistContent {
|
||||||
protected Status mainStatus;
|
protected Status mainStatus;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -187,4 +189,9 @@ public class ThreadFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.THREAD;
|
return Filter.FilterContext.THREAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return Uri.parse(mainStatus.url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
@@ -14,4 +15,11 @@ public abstract class AccountRelatedAccountListFragment extends PaginatedAccount
|
|||||||
account=Parcels.unwrap(getArguments().getParcelable("targetAccount"));
|
account=Parcels.unwrap(getArguments().getParcelable("targetAccount"));
|
||||||
setTitle("@"+account.acct);
|
setTitle("@"+account.acct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path(isInstanceAkkoma()
|
||||||
|
? "/users/" + account.id
|
||||||
|
: '@' + account.acct).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
@@ -23,7 +24,8 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
import org.joinmastodon.android.fragments.HasAccountID;
|
||||||
|
import org.joinmastodon.android.fragments.ListsFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||||
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
||||||
@@ -34,6 +36,7 @@ import org.joinmastodon.android.ui.OutlineProviders;
|
|||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -57,7 +60,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccountListFragment.AccountItem> {
|
public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccountListFragment.AccountItem> implements ProvidesAssistContent.ProvidesWebUri {
|
||||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||||
protected String accountID;
|
protected String accountID;
|
||||||
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
||||||
@@ -170,6 +173,16 @@ public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccou
|
|||||||
super.onApplyWindowInsets(insets);
|
super.onApplyWindowInsets(insets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
assistContent.setWebUri(getWebUri(getSession().getInstanceUri().buildUpon()));
|
||||||
|
}
|
||||||
|
|
||||||
protected class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
protected class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
public AccountsAdapter(){
|
public AccountsAdapter(){
|
||||||
super(imgLoader);
|
super(imgLoader);
|
||||||
@@ -387,7 +400,7 @@ public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccou
|
|||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putString("profileAccount", account.id);
|
args.putString("profileAccount", account.id);
|
||||||
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
||||||
Nav.go(getActivity(), ListTimelinesFragment.class, args);
|
Nav.go(getActivity(), ListsFragment.class, args);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -19,4 +20,10 @@ public class FollowerListFragment extends AccountRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetAccountFollowers(account.id, maxID, count);
|
return new GetAccountFollowers(account.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return super.getWebUri(base).buildUpon()
|
||||||
|
.appendPath(isInstanceAkkoma() ? "#followers" : "/followers").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -19,4 +20,10 @@ public class FollowingListFragment extends AccountRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetAccountFollowing(account.id, maxID, count);
|
return new GetAccountFollowing(account.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return super.getWebUri(base).buildUpon()
|
||||||
|
.appendPath(isInstanceAkkoma() ? "#followees" : "/following").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -18,4 +19,12 @@ public class StatusFavoritesListFragment extends StatusRelatedAccountListFragmen
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetStatusFavorites(status.id, maxID, count);
|
return new GetStatusFavorites(status.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
Uri statusUri = super.getWebUri(base);
|
||||||
|
return isInstanceAkkoma()
|
||||||
|
? statusUri
|
||||||
|
: statusUri.buildUpon().appendPath("favourites").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
@@ -18,4 +19,12 @@ public class StatusReblogsListFragment extends StatusRelatedAccountListFragment{
|
|||||||
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
|
||||||
return new GetStatusReblogs(status.id, maxID, count);
|
return new GetStatusReblogs(status.id, maxID, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
Uri statusUri = super.getWebUri(base);
|
||||||
|
return isInstanceAkkoma()
|
||||||
|
? statusUri
|
||||||
|
: statusUri.buildUpon().appendPath("reblogs").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.account_list;
|
package org.joinmastodon.android.fragments.account_list;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -18,4 +19,13 @@ public abstract class StatusRelatedAccountListFragment extends PaginatedAccountL
|
|||||||
protected boolean hasSubtitle(){
|
protected boolean hasSubtitle(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base
|
||||||
|
.encodedPath(isInstanceAkkoma()
|
||||||
|
? "/notice/" + status.id
|
||||||
|
: '@' + status.account.acct + '/' + status.id)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -52,4 +53,9 @@ public class BubbleTimelineFragment extends StatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.PUBLIC;
|
return Filter.FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? base.path("/main/bubble").build() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.joinmastodon.android.fragments.discover;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -27,6 +28,7 @@ import org.joinmastodon.android.ui.text.HtmlParser;
|
|||||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
import org.joinmastodon.android.ui.views.ProgressBarButton;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -49,7 +51,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class DiscoverAccountsFragment extends RecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop {
|
public class DiscoverAccountsFragment extends RecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||||
private GetAccountRelationships relationshipsRequest;
|
private GetAccountRelationships relationshipsRequest;
|
||||||
@@ -145,6 +147,16 @@ public class DiscoverAccountsFragment extends RecyclerFragment<DiscoverAccountsF
|
|||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/explore/suggestions").build();
|
||||||
|
}
|
||||||
|
|
||||||
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
public AccountsAdapter(){
|
public AccountsAdapter(){
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
@@ -26,6 +27,7 @@ import org.joinmastodon.android.ui.SimpleViewHolder;
|
|||||||
import org.joinmastodon.android.ui.tabs.TabLayout;
|
import org.joinmastodon.android.ui.tabs.TabLayout;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -37,7 +39,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|||||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, IsOnTop {
|
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, IsOnTop, ProvidesAssistContent {
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
@@ -50,7 +52,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
private ProgressBar searchProgress;
|
private ProgressBar searchProgress;
|
||||||
|
|
||||||
private DiscoverPostsFragment postsFragment;
|
private DiscoverPostsFragment postsFragment;
|
||||||
private TrendingHashtagsFragment hashtagsFragment;
|
private DiscoverHashtagsFragment hashtagsFragment;
|
||||||
private DiscoverNewsFragment newsFragment;
|
private DiscoverNewsFragment newsFragment;
|
||||||
private DiscoverAccountsFragment accountsFragment;
|
private DiscoverAccountsFragment accountsFragment;
|
||||||
private SearchFragment searchFragment;
|
private SearchFragment searchFragment;
|
||||||
@@ -118,7 +120,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
postsFragment=new DiscoverPostsFragment();
|
postsFragment=new DiscoverPostsFragment();
|
||||||
postsFragment.setArguments(args);
|
postsFragment.setArguments(args);
|
||||||
|
|
||||||
hashtagsFragment=new TrendingHashtagsFragment();
|
hashtagsFragment=new DiscoverHashtagsFragment();
|
||||||
hashtagsFragment.setArguments(args);
|
hashtagsFragment.setArguments(args);
|
||||||
|
|
||||||
newsFragment=new DiscoverNewsFragment();
|
newsFragment=new DiscoverNewsFragment();
|
||||||
@@ -321,6 +323,13 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
V.setVisibilityAnimated(searchClear, visible ? View.INVISIBLE : View.VISIBLE);
|
V.setVisibilityAnimated(searchClear, visible ? View.INVISIBLE : View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
callFragmentToProvideAssistContent(searchActive
|
||||||
|
? searchFragment
|
||||||
|
: getFragmentForPage(pager.getCurrentItem()), assistContent);
|
||||||
|
}
|
||||||
|
|
||||||
private class DiscoverPagerAdapter extends RecyclerView.Adapter<SimpleViewHolder>{
|
private class DiscoverPagerAdapter extends RecyclerView.Adapter<SimpleViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.joinmastodon.android.fragments.discover;
|
|||||||
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withHistoryParams;
|
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withHistoryParams;
|
||||||
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withoutHistoryParams;
|
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withoutHistoryParams;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -18,6 +19,7 @@ import org.joinmastodon.android.ui.DividerItemDecoration;
|
|||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.HashtagChartView;
|
import org.joinmastodon.android.ui.views.HashtagChartView;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -27,11 +29,11 @@ import me.grishka.appkit.api.SimpleCallback;
|
|||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class TrendingHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop {
|
public class DiscoverHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
|
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
|
||||||
|
|
||||||
public TrendingHashtagsFragment(){
|
public DiscoverHashtagsFragment(){
|
||||||
super(10);
|
super(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +78,16 @@ public class TrendingHashtagsFragment extends RecyclerFragment<Hashtag> implemen
|
|||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/explore/tags").build();
|
||||||
|
}
|
||||||
|
|
||||||
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
private class HashtagsAdapter extends RecyclerView.Adapter<HashtagViewHolder>{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -19,6 +20,7 @@ import org.joinmastodon.android.ui.OutlineProviders;
|
|||||||
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -35,7 +37,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class DiscoverNewsFragment extends RecyclerFragment<Card> implements ScrollableToTop, IsOnTop {
|
public class DiscoverNewsFragment extends RecyclerFragment<Card> implements ScrollableToTop, IsOnTop, ProvidesAssistContent.ProvidesWebUri {
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
|
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
|
||||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
|
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
|
||||||
@@ -88,6 +90,16 @@ public class DiscoverNewsFragment extends RecyclerFragment<Card> implements Scro
|
|||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccountID() {
|
||||||
|
return accountID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/explore/links").build();
|
||||||
|
}
|
||||||
|
|
||||||
private class LinksAdapter extends UsableRecyclerView.Adapter<LinkViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class LinksAdapter extends UsableRecyclerView.Adapter<LinkViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
public LinksAdapter(){
|
public LinksAdapter(){
|
||||||
super(imgLoader);
|
super(imgLoader);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -43,9 +44,13 @@ public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop
|
|||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.PUBLIC;
|
return Filter.FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return isInstanceAkkoma() ? null : base.path("/explore/posts").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -25,7 +26,6 @@ public class FederatedTimelineFragment extends StatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetPublicTimeline(false, false, refreshing ? null : maxID, count)
|
currentRequest=new GetPublicTimeline(false, false, refreshing ? null : maxID, count)
|
||||||
@@ -52,4 +52,9 @@ public class FederatedTimelineFragment extends StatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.PUBLIC;
|
return Filter.FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path(isInstanceAkkoma() ? "/main/all" : "/public").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -24,7 +26,6 @@ public class LocalTimelineFragment extends StatusListFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(int offset, int count){
|
protected void doLoadData(int offset, int count){
|
||||||
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count)
|
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count)
|
||||||
@@ -51,4 +52,9 @@ public class LocalTimelineFragment extends StatusListFragment {
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return Filter.FilterContext.PUBLIC;
|
return Filter.FilterContext.PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
return base.path(isInstanceAkkoma() ? "/main/public" : "/public/local").build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -316,6 +317,14 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult> impleme
|
|||||||
return isRecyclerViewOnTop(list);
|
return isRecyclerViewOnTop(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
Uri.Builder searchUri = base.path("/search");
|
||||||
|
return isInstanceAkkoma()
|
||||||
|
? searchUri.appendQueryParameter("query", currentQuery).build()
|
||||||
|
: searchUri.build();
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ProgressVisibilityListener{
|
public interface ProgressVisibilityListener{
|
||||||
void onProgressVisibilityChanged(boolean visible);
|
void onProgressVisibilityChanged(boolean visible);
|
||||||
|
|||||||
@@ -89,13 +89,6 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
return !UiUtils.isDarkTheme();
|
return !UiUtils.isDarkTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
|
||||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onUpdateToolbar(){
|
protected void onUpdateToolbar(){
|
||||||
super.onUpdateToolbar();
|
super.onUpdateToolbar();
|
||||||
@@ -110,7 +103,7 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onToolbarNavigationClick(){
|
public void onToolbarNavigationClick(){
|
||||||
new AccountSwitcherSheet(getActivity()).show();
|
new AccountSwitcherSheet(getActivity(), null).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
@@ -267,4 +268,11 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
protected Filter.FilterContext getFilterContext() {
|
protected Filter.FilterContext getFilterContext() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getWebUri(Uri.Builder base) {
|
||||||
|
if (reportStatus != null) return Uri.parse(reportStatus.url);
|
||||||
|
if (reportAccount != null) return Uri.parse(reportAccount.url);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,13 +259,14 @@ public class TimelineDefinition {
|
|||||||
public boolean isCompatible(AccountSession session) {
|
public boolean isCompatible(AccountSession session) {
|
||||||
// still enabling the bubble timeline for all pleroma/akkoma instances since i know of
|
// still enabling the bubble timeline for all pleroma/akkoma instances since i know of
|
||||||
// at least one instance that supports it, but doesn't list "bubble_timeline"
|
// at least one instance that supports it, but doesn't list "bubble_timeline"
|
||||||
return session.getInstance().isPleroma();
|
return session.getInstance().map(Instance::isPleroma).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean wantsDefault(AccountSession session) {
|
public boolean wantsDefault(AccountSession session) {
|
||||||
Instance instance = session.getInstance();
|
return session.getInstance()
|
||||||
return instance.isPleroma() && instance.pleroma.metadata.features.contains("bubble_timeline");
|
.map(i -> i.isPleroma() && i.pleroma.metadata.features.contains("bubble_timeline"))
|
||||||
|
.orElse(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package org.joinmastodon.android.ui;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -14,7 +14,7 @@ import android.view.WindowInsets;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.RadioButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
@@ -23,13 +23,21 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.fragments.HomeFragment;
|
||||||
|
import org.joinmastodon.android.fragments.SplashFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.ui.views.CheckableRelativeLayout;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
@@ -49,13 +57,24 @@ import me.grishka.appkit.views.UsableRecyclerView;
|
|||||||
|
|
||||||
public class AccountSwitcherSheet extends BottomSheet{
|
public class AccountSwitcherSheet extends BottomSheet{
|
||||||
private final Activity activity;
|
private final Activity activity;
|
||||||
|
private final HomeFragment fragment;
|
||||||
|
private final BiConsumer<String, Boolean> onClick;
|
||||||
|
private final boolean externalShare, openInApp;
|
||||||
private UsableRecyclerView list;
|
private UsableRecyclerView list;
|
||||||
private List<WrappedAccount> accounts;
|
private List<WrappedAccount> accounts;
|
||||||
private ListImageLoaderWrapper imgLoader;
|
private ListImageLoaderWrapper imgLoader;
|
||||||
|
|
||||||
public AccountSwitcherSheet(@NonNull Activity activity){
|
public AccountSwitcherSheet(@NonNull Activity activity, @Nullable HomeFragment fragment){
|
||||||
|
this(activity, fragment, false, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountSwitcherSheet(@NonNull Activity activity, @Nullable HomeFragment fragment, boolean externalShare, boolean openInApp, BiConsumer<String, Boolean> onClick){
|
||||||
super(activity);
|
super(activity);
|
||||||
this.activity=activity;
|
this.activity=activity;
|
||||||
|
this.fragment=fragment;
|
||||||
|
this.externalShare = externalShare;
|
||||||
|
this.openInApp = openInApp;
|
||||||
|
this.onClick = onClick;
|
||||||
|
|
||||||
accounts=AccountSessionManager.getInstance().getLoggedInAccounts().stream().map(WrappedAccount::new).collect(Collectors.toList());
|
accounts=AccountSessionManager.getInstance().getLoggedInAccounts().stream().map(WrappedAccount::new).collect(Collectors.toList());
|
||||||
|
|
||||||
@@ -67,41 +86,59 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
||||||
View handle=new View(activity);
|
View handle=new View(activity);
|
||||||
handle.setBackgroundResource(R.drawable.bg_bottom_sheet_handle);
|
handle.setBackgroundResource(R.drawable.bg_bottom_sheet_handle);
|
||||||
|
handle.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(36)));
|
||||||
|
|
||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(handle));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(handle));
|
||||||
|
|
||||||
|
if (externalShare) {
|
||||||
|
FrameLayout shareHeading = new FrameLayout(activity);
|
||||||
|
activity.getLayoutInflater().inflate(R.layout.item_external_share_heading, shareHeading);
|
||||||
|
((TextView) shareHeading.findViewById(R.id.title)).setText(openInApp
|
||||||
|
? R.string.sk_external_share_or_open_title
|
||||||
|
: R.string.sk_external_share_title);
|
||||||
|
adapter.addAdapter(new SingleViewRecyclerAdapter(shareHeading));
|
||||||
|
|
||||||
|
setOnDismissListener((d) -> activity.finish());
|
||||||
|
}
|
||||||
|
|
||||||
adapter.addAdapter(new AccountsAdapter());
|
adapter.addAdapter(new AccountsAdapter());
|
||||||
AccountViewHolder holder=new AccountViewHolder();
|
|
||||||
holder.more.setVisibility(View.GONE);
|
if (!externalShare) {
|
||||||
holder.currentIcon.setVisibility(View.GONE);
|
adapter.addAdapter(new ClickableSingleViewRecyclerAdapter(makeSimpleListItem(R.string.add_account, R.drawable.ic_add_24px), () -> {
|
||||||
holder.name.setText(R.string.add_account);
|
Nav.go(activity, CustomWelcomeFragment.class, null);
|
||||||
holder.avatar.setScaleType(ImageView.ScaleType.CENTER);
|
dismiss();
|
||||||
holder.avatar.setImageResource(R.drawable.ic_fluent_add_circle_24_filled);
|
}));
|
||||||
holder.avatar.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(activity, android.R.attr.textColorPrimary)));
|
// disabled in megalodon
|
||||||
adapter.addAdapter(new ClickableSingleViewRecyclerAdapter(holder.itemView, ()->{
|
// adapter.addAdapter(new ClickableSingleViewRecyclerAdapter(makeSimpleListItem(R.string.log_out_all_accounts, R.drawable.ic_fluent_person_arrow_right_24_filled), this::confirmLogOutAll));
|
||||||
Nav.go(activity, CustomWelcomeFragment.class, null);
|
}
|
||||||
dismiss();
|
|
||||||
}));
|
|
||||||
|
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
DividerItemDecoration divider=new DividerItemDecoration(activity, R.attr.colorPollVoted, .5f, 72, 16, DividerItemDecoration.NOT_FIRST);
|
|
||||||
divider.setDrawBelowLastItem(true);
|
|
||||||
list.addItemDecoration(divider);
|
|
||||||
|
|
||||||
FrameLayout content=new FrameLayout(activity);
|
FrameLayout content=new FrameLayout(activity);
|
||||||
content.setBackgroundResource(R.drawable.bg_bottom_sheet);
|
content.setBackgroundResource(R.drawable.bg_bottom_sheet);
|
||||||
content.addView(list);
|
content.addView(list);
|
||||||
setContentView(content);
|
setContentView(content);
|
||||||
setNavigationBarBackground(new ColorDrawable(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground)), !UiUtils.isDarkTheme());
|
setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(activity, R.attr.colorM3Surface),
|
||||||
|
UiUtils.getThemeColor(activity, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void confirmLogOut(String accountID){
|
private void confirmLogOut(String accountID){
|
||||||
|
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
new M3AlertDialogBuilder(activity)
|
new M3AlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.log_out)
|
.setMessage(activity.getString(R.string.confirm_log_out, session.getFullUsername()))
|
||||||
.setMessage(R.string.confirm_log_out)
|
|
||||||
.setPositiveButton(R.string.log_out, (dialog, which) -> logOut(accountID))
|
.setPositiveButton(R.string.log_out, (dialog, which) -> logOut(accountID))
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void confirmLogOutAll(){
|
||||||
|
new M3AlertDialogBuilder(activity)
|
||||||
|
.setMessage(R.string.confirm_log_out_all_accounts)
|
||||||
|
.setPositiveButton(R.string.log_out, (dialog, which) -> logOutAll())
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void logOut(String accountID){
|
private void logOut(String accountID){
|
||||||
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
new RevokeOauthToken(session.app.clientId, session.app.clientSecret, session.token.accessToken)
|
new RevokeOauthToken(session.app.clientId, session.app.clientSecret, session.token.accessToken)
|
||||||
@@ -120,9 +157,52 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
.exec(accountID);
|
.exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logOutAll(){
|
||||||
|
final ProgressDialog progress=new ProgressDialog(activity);
|
||||||
|
progress.setMessage(activity.getString(R.string.loading));
|
||||||
|
progress.setCancelable(false);
|
||||||
|
progress.show();
|
||||||
|
ArrayList<AccountSession> sessions=new ArrayList<>(AccountSessionManager.getInstance().getLoggedInAccounts());
|
||||||
|
for(AccountSession session:sessions){
|
||||||
|
new RevokeOauthToken(session.app.clientId, session.app.clientSecret, session.token.accessToken)
|
||||||
|
.setCallback(new Callback<>(){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object result){
|
||||||
|
AccountSessionManager.getInstance().removeAccount(session.getID());
|
||||||
|
sessions.remove(session);
|
||||||
|
if(sessions.isEmpty()){
|
||||||
|
progress.dismiss();
|
||||||
|
Nav.goClearingStack(activity, SplashFragment.class, null);
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error){
|
||||||
|
AccountSessionManager.getInstance().removeAccount(session.getID());
|
||||||
|
sessions.remove(session);
|
||||||
|
if(sessions.isEmpty()){
|
||||||
|
progress.dismiss();
|
||||||
|
Nav.goClearingStack(activity, SplashFragment.class, null);
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(session.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onLoggedOut(String accountID){
|
private void onLoggedOut(String accountID){
|
||||||
AccountSessionManager.getInstance().removeAccount(accountID);
|
AccountSessionManager.getInstance().removeAccount(accountID);
|
||||||
dismiss();
|
String activeAccountID = fragment != null
|
||||||
|
? fragment.getAccountID()
|
||||||
|
: AccountSessionManager.getInstance().getLastActiveAccountID();
|
||||||
|
if (accountID.equals(activeAccountID)) {
|
||||||
|
activity.finish();
|
||||||
|
activity.startActivity(new Intent(activity, MainActivity.class));
|
||||||
|
} else {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,6 +220,13 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private View makeSimpleListItem(@StringRes int title, @DrawableRes int icon){
|
||||||
|
TextView tv=(TextView) activity.getLayoutInflater().inflate(R.layout.item_text_with_icon, list, false);
|
||||||
|
tv.setText(title);
|
||||||
|
tv.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, 0, 0, 0);
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
private class AccountsAdapter extends UsableRecyclerView.Adapter<AccountViewHolder> implements ImageLoaderRecyclerAdapter{
|
||||||
public AccountsAdapter(){
|
public AccountsAdapter(){
|
||||||
super(imgLoader);
|
super(imgLoader);
|
||||||
@@ -173,45 +260,42 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccountViewHolder extends BindableViewHolder<AccountSession> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable{
|
private class AccountViewHolder extends BindableViewHolder<AccountSession> implements ImageLoaderViewHolder, UsableRecyclerView.Clickable, UsableRecyclerView.LongClickable{
|
||||||
private final TextView name;
|
private final TextView name, username;
|
||||||
private final ImageView avatar;
|
private final ImageView avatar;
|
||||||
private final ImageButton more;
|
private final CheckableRelativeLayout view;
|
||||||
private final View currentIcon;
|
private final View radioButton, extraBtnWrap;
|
||||||
private final PopupMenu menu;
|
private final ImageButton extraBtn;
|
||||||
|
|
||||||
public AccountViewHolder(){
|
public AccountViewHolder(){
|
||||||
super(activity, R.layout.item_account_switcher, list);
|
super(activity, R.layout.item_account_switcher, list);
|
||||||
name=findViewById(R.id.name);
|
name=findViewById(R.id.name);
|
||||||
|
username=findViewById(R.id.username);
|
||||||
|
radioButton=findViewById(R.id.radiobtn);
|
||||||
|
radioButton.setBackground(new RadioButton(activity).getButtonDrawable());
|
||||||
avatar=findViewById(R.id.avatar);
|
avatar=findViewById(R.id.avatar);
|
||||||
more=findViewById(R.id.more);
|
avatar.setOutlineProvider(OutlineProviders.roundedRect(OutlineProviders.RADIUS_MEDIUM));
|
||||||
currentIcon=findViewById(R.id.current);
|
|
||||||
|
|
||||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
|
|
||||||
avatar.setClipToOutline(true);
|
avatar.setClipToOutline(true);
|
||||||
|
view=(CheckableRelativeLayout) itemView;
|
||||||
menu=new PopupMenu(activity, more);
|
extraBtnWrap = findViewById(R.id.extra_btn_wrap);
|
||||||
menu.inflate(R.menu.account_switcher);
|
extraBtn = findViewById(R.id.extra_btn);
|
||||||
menu.setOnMenuItemClickListener(item1 -> {
|
extraBtn.setOnClickListener(this::onExtraBtnClick);
|
||||||
confirmLogOut(item.getID());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
more.setOnClickListener(v->menu.show());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@Override
|
@Override
|
||||||
public void onBind(AccountSession item){
|
public void onBind(AccountSession item){
|
||||||
name.setText("@"+item.self.username+"@"+item.domain);
|
name.setText(item.self.displayName);
|
||||||
if(AccountSessionManager.getInstance().getLastActiveAccountID().equals(item.getID())){
|
username.setText(item.getFullUsername());
|
||||||
more.setVisibility(View.GONE);
|
radioButton.setVisibility(externalShare ? View.GONE : View.VISIBLE);
|
||||||
currentIcon.setVisibility(View.VISIBLE);
|
extraBtnWrap.setVisibility(externalShare && openInApp ? View.VISIBLE : View.GONE);
|
||||||
}else{
|
if (externalShare) view.setCheckable(false);
|
||||||
more.setVisibility(View.VISIBLE);
|
else {
|
||||||
currentIcon.setVisibility(View.GONE);
|
String accountId = fragment != null
|
||||||
|
? fragment.getAccountID()
|
||||||
|
: AccountSessionManager.getInstance().getLastActiveAccountID();
|
||||||
|
view.setChecked(accountId.equals(item.getID()));
|
||||||
}
|
}
|
||||||
menu.getMenu().findItem(R.id.log_out).setTitle(activity.getString(R.string.log_out_account, "@"+item.self.username));
|
|
||||||
UiUtils.enablePopupMenuIcons(activity, menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,12 +310,32 @@ public class AccountSwitcherSheet extends BottomSheet{
|
|||||||
setImage(index, null);
|
setImage(index, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onExtraBtnClick(View view) {
|
||||||
|
setOnDismissListener(null);
|
||||||
|
dismiss();
|
||||||
|
onClick.accept(item.getID(), true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick(){
|
||||||
|
setOnDismissListener(null);
|
||||||
|
if (onClick != null) {
|
||||||
|
dismiss();
|
||||||
|
onClick.accept(item.getID(), false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
||||||
activity.finish();
|
activity.finish();
|
||||||
activity.startActivity(new Intent(activity, MainActivity.class));
|
activity.startActivity(new Intent(activity, MainActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(){
|
||||||
|
if (externalShare) return false;
|
||||||
|
confirmLogOut(item.getID());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WrappedAccount{
|
private static class WrappedAccount{
|
||||||
|
|||||||
@@ -8,7 +8,15 @@ import android.view.ViewOutlineProvider;
|
|||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class OutlineProviders{
|
public class OutlineProviders{
|
||||||
private static SparseArray<ViewOutlineProvider> roundedRects=new SparseArray<>();
|
private static final SparseArray<ViewOutlineProvider> roundedRects=new SparseArray<>();
|
||||||
|
private static final SparseArray<ViewOutlineProvider> topRoundedRects=new SparseArray<>();
|
||||||
|
private static final SparseArray<ViewOutlineProvider> endRoundedRects=new SparseArray<>();
|
||||||
|
|
||||||
|
public static final int RADIUS_XSMALL=4;
|
||||||
|
public static final int RADIUS_SMALL=8;
|
||||||
|
public static final int RADIUS_MEDIUM=12;
|
||||||
|
public static final int RADIUS_LARGE=16;
|
||||||
|
public static final int RADIUS_XLARGE=28;
|
||||||
|
|
||||||
private OutlineProviders(){
|
private OutlineProviders(){
|
||||||
//no instance
|
//no instance
|
||||||
@@ -21,6 +29,12 @@ public class OutlineProviders{
|
|||||||
outline.setAlpha(view.getAlpha());
|
outline.setAlpha(view.getAlpha());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
public static final ViewOutlineProvider OVAL=new ViewOutlineProvider(){
|
||||||
|
@Override
|
||||||
|
public void getOutline(View view, Outline outline){
|
||||||
|
outline.setOval(0, 0, view.getWidth(), view.getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static ViewOutlineProvider roundedRect(int dp){
|
public static ViewOutlineProvider roundedRect(int dp){
|
||||||
ViewOutlineProvider provider=roundedRects.get(dp);
|
ViewOutlineProvider provider=roundedRects.get(dp);
|
||||||
@@ -31,6 +45,24 @@ public class OutlineProviders{
|
|||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ViewOutlineProvider topRoundedRect(int dp){
|
||||||
|
ViewOutlineProvider provider=topRoundedRects.get(dp);
|
||||||
|
if(provider!=null)
|
||||||
|
return provider;
|
||||||
|
provider=new TopRoundRectOutlineProvider(V.dp(dp));
|
||||||
|
topRoundedRects.put(dp, provider);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewOutlineProvider endRoundedRect(int dp){
|
||||||
|
ViewOutlineProvider provider=endRoundedRects.get(dp);
|
||||||
|
if(provider!=null)
|
||||||
|
return provider;
|
||||||
|
provider=new EndRoundRectOutlineProvider(V.dp(dp));
|
||||||
|
endRoundedRects.put(dp, provider);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
private static class RoundRectOutlineProvider extends ViewOutlineProvider{
|
private static class RoundRectOutlineProvider extends ViewOutlineProvider{
|
||||||
private final int radius;
|
private final int radius;
|
||||||
|
|
||||||
@@ -43,4 +75,34 @@ public class OutlineProviders{
|
|||||||
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius);
|
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TopRoundRectOutlineProvider extends ViewOutlineProvider{
|
||||||
|
private final int radius;
|
||||||
|
|
||||||
|
private TopRoundRectOutlineProvider(int radius){
|
||||||
|
this.radius=radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getOutline(View view, Outline outline){
|
||||||
|
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight()+radius, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class EndRoundRectOutlineProvider extends ViewOutlineProvider{
|
||||||
|
private final int radius;
|
||||||
|
|
||||||
|
private EndRoundRectOutlineProvider(int radius){
|
||||||
|
this.radius=radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getOutline(View view, Outline outline){
|
||||||
|
if(view.getLayoutDirection()==View.LAYOUT_DIRECTION_RTL){
|
||||||
|
outline.setRoundRect(-radius, 0, view.getWidth(), view.getHeight(), radius);
|
||||||
|
}else{
|
||||||
|
outline.setRoundRect(0, 0, view.getWidth()+radius, view.getHeight(), radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.parentFragment.getAccountID());
|
args.putString("account", item.parentFragment.getAccountID());
|
||||||
args.putString("id", item.status.id);
|
args.putString("id", item.status.id);
|
||||||
|
args.putString("url", item.status.url);
|
||||||
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -24,8 +22,6 @@ import android.widget.PopupMenu;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
@@ -36,7 +32,7 @@ import org.joinmastodon.android.api.session.AccountSession;
|
|||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.ComposeFragment;
|
import org.joinmastodon.android.fragments.ComposeFragment;
|
||||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
import org.joinmastodon.android.fragments.ListsFragment;
|
||||||
import org.joinmastodon.android.fragments.NotificationsListFragment;
|
import org.joinmastodon.android.fragments.NotificationsListFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
@@ -44,12 +40,10 @@ import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
|||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Announcement;
|
import org.joinmastodon.android.model.Announcement;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.ContentType;
|
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.model.StatusPrivacy;
|
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
@@ -59,7 +53,6 @@ import java.time.Instant;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.FormatStyle;
|
import java.time.format.FormatStyle;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -284,7 +277,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
args.putString("account", item.parentFragment.getAccountID());
|
args.putString("account", item.parentFragment.getAccountID());
|
||||||
args.putString("profileAccount", account.id);
|
args.putString("profileAccount", account.id);
|
||||||
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
||||||
Nav.go(item.parentFragment.getActivity(), ListTimelinesFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ListsFragment.class, args);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Fragment;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
@@ -110,6 +111,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -948,8 +950,8 @@ public class UiUtils {
|
|||||||
|
|
||||||
public static String getInstanceName(String accountID) {
|
public static String getInstanceName(String accountID) {
|
||||||
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
Instance instance = session.getInstance();
|
Optional<Instance> instance = session.getInstance();
|
||||||
return instance != null && !instance.title.isBlank() ? instance.title : session.domain;
|
return instance.isPresent() && !instance.get().title.isBlank() ? instance.get().title : session.domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void pickAccount(Context context, String exceptFor, @StringRes int titleRes, @DrawableRes int iconRes, Consumer<AccountSession> sessionConsumer, Consumer<AlertDialog.Builder> transformDialog) {
|
public static void pickAccount(Context context, String exceptFor, @StringRes int titleRes, @DrawableRes int iconRes, Consumer<AccountSession> sessionConsumer, Consumer<AlertDialog.Builder> transformDialog) {
|
||||||
@@ -1080,6 +1082,13 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void openURL(Context context, String accountID, String url, boolean launchBrowser) {
|
public static void openURL(Context context, String accountID, String url, boolean launchBrowser) {
|
||||||
|
lookupURL(context, accountID, url, launchBrowser, (clazz, args) -> {
|
||||||
|
if (clazz == null) return;
|
||||||
|
Nav.go((Activity) context, clazz, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void lookupURL(Context context, String accountID, String url, boolean launchBrowser, BiConsumer<Class<? extends Fragment>, Bundle> go) {
|
||||||
Uri uri = Uri.parse(url);
|
Uri uri = Uri.parse(url);
|
||||||
List<String> path = uri.getPathSegments();
|
List<String> path = uri.getPathSegments();
|
||||||
if (accountID != null && "https".equals(uri.getScheme())) {
|
if (accountID != null && "https".equals(uri.getScheme())) {
|
||||||
@@ -1091,13 +1100,14 @@ public class UiUtils {
|
|||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putParcelable("status", Parcels.wrap(result));
|
args.putParcelable("status", Parcels.wrap(result));
|
||||||
Nav.go((Activity) context, ThreadFragment.class, args);
|
go.accept(ThreadFragment.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error) {
|
public void onError(ErrorResponse error) {
|
||||||
error.showToast(context);
|
error.showToast(context);
|
||||||
if (launchBrowser) launchWebBrowser(context, url);
|
if (launchBrowser) launchWebBrowser(context, url);
|
||||||
|
go.accept(null, null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.wrapProgress((Activity) context, R.string.loading, true,
|
.wrapProgress((Activity) context, R.string.loading, true,
|
||||||
@@ -1113,27 +1123,26 @@ public class UiUtils {
|
|||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
if (!results.statuses.isEmpty()) {
|
if (!results.statuses.isEmpty()) {
|
||||||
args.putParcelable("status", Parcels.wrap(results.statuses.get(0)));
|
args.putParcelable("status", Parcels.wrap(results.statuses.get(0)));
|
||||||
Nav.go((Activity) context, ThreadFragment.class, args);
|
go.accept(ThreadFragment.class, args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Optional<Account> account = results.accounts.stream()
|
Optional<Account> account = results.accounts.stream()
|
||||||
.filter(a -> uri.equals(Uri.parse(a.url))).findAny();
|
.filter(a -> uri.equals(Uri.parse(a.url))).findAny();
|
||||||
if (account.isPresent()) {
|
if (account.isPresent()) {
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(account.get()));
|
args.putParcelable("profileAccount", Parcels.wrap(account.get()));
|
||||||
Nav.go((Activity) context, ProfileFragment.class, args);
|
go.accept(ProfileFragment.class, args);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (launchBrowser) {
|
|
||||||
launchWebBrowser(context, url);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (launchBrowser) launchWebBrowser(context, url);
|
||||||
Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
|
||||||
|
go.accept(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(ErrorResponse error) {
|
public void onError(ErrorResponse error) {
|
||||||
error.showToast(context);
|
error.showToast(context);
|
||||||
if (launchBrowser) launchWebBrowser(context, url);
|
if (launchBrowser) launchWebBrowser(context, url);
|
||||||
|
go.accept(null, null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.wrapProgress((Activity) context, R.string.loading, true,
|
.wrapProgress((Activity) context, R.string.loading, true,
|
||||||
@@ -1142,7 +1151,8 @@ public class UiUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
launchWebBrowser(context, url);
|
if (launchBrowser) launchWebBrowser(context, url);
|
||||||
|
go.accept(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyText(View v, String text) {
|
public static void copyText(View v, String text) {
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
import android.widget.Checkable;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
|
public class CheckableRelativeLayout extends RelativeLayout implements Checkable{
|
||||||
|
private boolean checked, checkable = true;
|
||||||
|
private static final int[] CHECKED_STATE_SET = {
|
||||||
|
android.R.attr.state_checked
|
||||||
|
};
|
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context){
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context, AttributeSet attrs){
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle){
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChecked(boolean checked){
|
||||||
|
this.checked=checked;
|
||||||
|
refreshDrawableState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCheckable(boolean checkable) {
|
||||||
|
this.checkable = checkable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked(){
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toggle(){
|
||||||
|
setChecked(!checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int[] onCreateDrawableState(int extraSpace) {
|
||||||
|
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
|
||||||
|
if (isChecked()) {
|
||||||
|
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
|
||||||
|
}
|
||||||
|
return drawableState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info){
|
||||||
|
super.onInitializeAccessibilityNodeInfo(info);
|
||||||
|
info.setCheckable(checkable);
|
||||||
|
info.setChecked(checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.joinmastodon.android.utils;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.app.assist.AssistContent;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.fragments.HasAccountID;
|
||||||
|
|
||||||
|
public interface ProvidesAssistContent {
|
||||||
|
void onProvideAssistContent(AssistContent assistContent);
|
||||||
|
|
||||||
|
default boolean callFragmentToProvideAssistContent(Fragment fragment, AssistContent assistContent) {
|
||||||
|
if (fragment instanceof ProvidesAssistContent assistiveFragment) {
|
||||||
|
assistiveFragment.onProvideAssistContent(assistContent);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProvidesWebUri extends ProvidesAssistContent, HasAccountID {
|
||||||
|
Uri getWebUri(Uri.Builder base);
|
||||||
|
|
||||||
|
default Uri.Builder getUriBuilder() {
|
||||||
|
return getSession().getInstanceUri().buildUpon();
|
||||||
|
}
|
||||||
|
|
||||||
|
default void onProvideAssistContent(AssistContent assistContent) {
|
||||||
|
assistContent.setWebUri(getWebUri(getUriBuilder()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" android:viewportWidth="28" android:viewportHeight="28">
|
||||||
|
<path android:pathData="M18.27 3.21l7.5 7.25c0.073 0.07 0.13 0.154 0.17 0.247C25.98 10.8 26 10.9 26 11c0 0.101-0.02 0.201-0.06 0.294-0.04 0.093-0.097 0.176-0.17 0.246l-7.5 7.25c-0.069 0.068-0.15 0.121-0.239 0.157-0.09 0.037-0.185 0.055-0.281 0.053-0.1 0-0.198-0.02-0.29-0.06-0.136-0.056-0.252-0.152-0.334-0.275C17.044 18.542 17 18.398 17 18.25v-3.74c-6.7 0.27-9.52 4.02-9.64 4.18-0.096 0.126-0.227 0.22-0.378 0.268-0.15 0.048-0.311 0.049-0.462 0.003-0.15-0.049-0.282-0.144-0.375-0.271C6.052 18.562 6 18.408 6 18.25c0-8.02 6.59-10.48 11-10.73V3.75c0-0.147 0.044-0.291 0.126-0.414s0.198-0.218 0.334-0.275c0.135-0.059 0.284-0.075 0.428-0.049 0.144 0.027 0.277 0.096 0.382 0.199zm0.23 10.54v2.71L24.17 11 18.5 5.52v2.73c-0.003 0.199-0.082 0.388-0.223 0.528-0.14 0.14-0.329 0.22-0.527 0.223-0.97 0-8.85 0.22-10.09 7.28 2.876-2.24 6.447-3.401 10.09-3.28 0.198 0.002 0.387 0.082 0.527 0.222s0.22 0.33 0.223 0.527zm4.223 5.473c0.14-0.14 0.329-0.22 0.527-0.223 0.198 0.003 0.387 0.083 0.527 0.223s0.22 0.33 0.223 0.527v0.5c0 1.26-0.5 2.468-1.391 3.36-0.891 0.89-2.1 1.39-3.359 1.39H7.75c-1.26 0-2.468-0.5-3.359-1.39C3.501 22.717 3 21.51 3 20.25V8.75c0-1.26 0.5-2.468 1.391-3.358C5.282 4.5 6.491 4 7.75 4h4.5c0.199 0 0.39 0.08 0.53 0.22C12.921 4.36 13 4.552 13 4.75c0 0.2-0.079 0.39-0.22 0.53-0.14 0.141-0.331 0.22-0.53 0.22h-4.5C6.889 5.503 6.064 5.846 5.455 6.455 4.845 7.065 4.503 7.89 4.5 8.751v11.5c0.003 0.86 0.346 1.686 0.955 2.295S6.889 23.498 7.75 23.5h11.5c0.861-0.002 1.686-0.345 2.295-0.954 0.61-0.61 0.952-1.434 0.955-2.296v-0.5c0.003-0.198 0.082-0.387 0.223-0.527z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
||||||
@@ -1,44 +1,81 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<org.joinmastodon.android.ui.views.CheckableRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingRight="20dp"
|
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="32dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="40dp"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
android:importantForAccessibility="no"/>
|
android:importantForAccessibility="no"/>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/name"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"/>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/current"
|
android:id="@+id/radiobtn"
|
||||||
android:layout_width="24dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="32dp"
|
||||||
android:background="@drawable/ic_fluent_checkmark_24_filled"
|
android:layout_centerInParent="true"
|
||||||
android:backgroundTint="?android:textColorSecondary"
|
android:layout_toStartOf="@+id/extra_btn_wrap"
|
||||||
android:contentDescription="@string/current_account"/>
|
android:layout_alignWithParentIfMissing="true"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:duplicateParentState="true" />
|
||||||
|
|
||||||
<ImageButton
|
<FrameLayout
|
||||||
android:id="@+id/more"
|
android:id="@id/extra_btn_wrap"
|
||||||
android:layout_width="24dp"
|
android:layout_width="72dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="72dp"
|
||||||
android:src="@drawable/ic_fluent_more_vertical_24_regular"
|
android:layout_alignParentEnd="true"
|
||||||
android:tint="?android:textColorSecondary"
|
android:layout_marginStart="12dp"
|
||||||
android:contentDescription="@string/more_options"
|
android:visibility="gone">
|
||||||
android:background="?android:selectableItemBackgroundBorderless"/>
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_gravity="center_vertical|start"
|
||||||
|
android:background="?colorPollVoted" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/extra_btn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="@string/sk_open_in_app"
|
||||||
|
android:tooltipText="@string/sk_open_in_app"
|
||||||
|
android:src="@drawable/ic_fluent_open_24_regular"
|
||||||
|
android:background="?android:selectableItemBackground" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_toEndOf="@id/avatar"
|
||||||
|
android:layout_toStartOf="@id/radiobtn"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/m3_body_large"
|
||||||
|
android:textColor="?colorM3OnSurface"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?colorM3OnSurfaceVariant"
|
||||||
|
android:textAppearance="@style/m3_body_medium"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:ellipsize="end"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</org.joinmastodon.android.ui.views.CheckableRelativeLayout>
|
||||||
30
mastodon/src/main/res/layout/item_external_share_heading.xml
Normal file
30
mastodon/src/main/res/layout/item_external_share_heading.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:src="@drawable/ic_fluent_share_28_regular"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
tools:ignore="RtlSymmetry" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/sheet_title"
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sk_external_share_or_open_title"
|
||||||
|
android:textColor="?colorM3OnSurface" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
15
mastodon/src/main/res/layout/item_text_with_icon.xml
Normal file
15
mastodon/src/main/res/layout/item_text_with_icon.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:textColor="?colorM3OnSurface"
|
||||||
|
android:textAppearance="@style/m3_body_large"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingRight="24dp"
|
||||||
|
android:drawablePadding="24dp"
|
||||||
|
android:drawableTint="?colorM3OnSurfaceVariant"
|
||||||
|
tools:text="List Item"/>
|
||||||
@@ -275,4 +275,15 @@
|
|||||||
<string name="sk_settings_confirm_before_reblog">Confirma antes de impulsar</string>
|
<string name="sk_settings_confirm_before_reblog">Confirma antes de impulsar</string>
|
||||||
<string name="sk_reacted_with">Redactado con %s</string>
|
<string name="sk_reacted_with">Redactado con %s</string>
|
||||||
<string name="sk_reacted">redactado</string>
|
<string name="sk_reacted">redactado</string>
|
||||||
|
<string name="sk_content_type_unspecified">Non especificado</string>
|
||||||
|
<string name="sk_content_type_plain">Texto plano</string>
|
||||||
|
<string name="sk_content_type_html">HTML</string>
|
||||||
|
<string name="sk_content_type_bbcode">BBCode</string>
|
||||||
|
<string name="sk_content_type_mfm">MFM</string>
|
||||||
|
<string name="sk_settings_content_types">Activar o formato de publicacións</string>
|
||||||
|
<string name="sk_settings_default_content_type">Tipo de contido por defecto</string>
|
||||||
|
<string name="sk_settings_default_content_type_explanation">Isto permítelle ter un tipo de contido preseleccionado á hora de crear novas publicacións, sobrescribindo o valor establecido en \"Publicar preferencias\".</string>
|
||||||
|
<string name="sk_content_type">Tipo de contido</string>
|
||||||
|
<string name="sk_content_type_markdown">Markdown</string>
|
||||||
|
<string name="sk_settings_content_types_explanation">Permite configurar un tipo de contido como Markdown ao crear unha publicación. Teña en conta que non tódalas instancias soportan isto.</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -251,4 +251,7 @@
|
|||||||
<string name="sk_settings_hide_interaction">Verberg interactie knoppen</string>
|
<string name="sk_settings_hide_interaction">Verberg interactie knoppen</string>
|
||||||
<string name="sk_follow_as">Volgen met ander account</string>
|
<string name="sk_follow_as">Volgen met ander account</string>
|
||||||
<string name="sk_followed_as">Gevolgd met %s</string>
|
<string name="sk_followed_as">Gevolgd met %s</string>
|
||||||
|
<string name="sk_quoting_user">Quoting %s</string>
|
||||||
|
<string name="sk_settings_reply_visibility">Zichtbaarheid reactie</string>
|
||||||
|
<string name="sk_settings_reply_visibility_all">Alle reacties</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -4,32 +4,57 @@
|
|||||||
|
|
||||||
<color name="m3_navigation_bar_bg">@android:color/system_neutral1_50</color>
|
<color name="m3_navigation_bar_bg">@android:color/system_neutral1_50</color>
|
||||||
|
|
||||||
<color name="m3_gray_900">@android:color/system_neutral1_900</color>
|
<color name="m3_neutral1_900">@android:color/system_neutral1_900</color>
|
||||||
<color name="m3_gray_800t">@android:color/system_neutral1_800</color>
|
<color name="m3_neutral1_800t">@android:color/system_neutral1_800</color>
|
||||||
<color name="m3_gray_800">@android:color/system_neutral1_800</color>
|
<color name="m3_neutral1_800">@android:color/system_neutral1_800</color>
|
||||||
<color name="m3_gray_700">@android:color/system_neutral1_700</color>
|
<color name="m3_neutral1_700">@android:color/system_neutral1_700</color>
|
||||||
<color name="m3_gray_600">@android:color/system_neutral1_600</color>
|
<color name="m3_neutral1_600">@android:color/system_neutral1_600</color>
|
||||||
<color name="m3_gray_500">@android:color/system_neutral1_500</color>
|
<color name="m3_neutral1_500">@android:color/system_neutral1_500</color>
|
||||||
<color name="m3_gray_400">@android:color/system_neutral1_400</color>
|
<color name="m3_neutral1_400">@android:color/system_neutral1_400</color>
|
||||||
<color name="m3_gray_300">@android:color/system_neutral1_300</color>
|
<color name="m3_neutral1_300">@android:color/system_neutral1_300</color>
|
||||||
<color name="m3_gray_200">@android:color/system_neutral1_200</color>
|
<color name="m3_neutral1_200">@android:color/system_neutral1_200</color>
|
||||||
<color name="m3_gray_100">@android:color/system_neutral1_100</color>
|
<color name="m3_neutral1_100">@android:color/system_neutral1_100</color>
|
||||||
<color name="m3_gray_50t">@android:color/system_neutral1_50</color>
|
<color name="m3_neutral1_50t">@android:color/system_neutral1_50</color>
|
||||||
<color name="m3_gray_50">@android:color/system_neutral1_50</color>
|
<color name="m3_neutral1_50">@android:color/system_neutral1_50</color>
|
||||||
<color name="m3_gray_25">@android:color/system_neutral1_10</color>
|
<color name="m3_neutral1_25">@android:color/system_neutral1_10</color>
|
||||||
|
|
||||||
<color name="m3_primary_25">@android:color/system_accent1_10</color>
|
<color name="m3_accent1_25">@android:color/system_accent1_10</color>
|
||||||
<color name="m3_primary_50">@android:color/system_accent1_50</color>
|
<color name="m3_accent1_50">@android:color/system_accent1_50</color>
|
||||||
<color name="m3_primary_100">@android:color/system_accent1_100</color>
|
<color name="m3_accent1_100">@android:color/system_accent1_100</color>
|
||||||
<color name="m3_primary_200">@android:color/system_accent1_200</color>
|
<color name="m3_accent1_200">@android:color/system_accent1_200</color>
|
||||||
<color name="m3_primary_300">@android:color/system_accent1_300</color>
|
<color name="m3_accent1_300">@android:color/system_accent1_300</color>
|
||||||
<color name="m3_primary_400">@android:color/system_accent1_400</color>
|
<color name="m3_accent1_400">@android:color/system_accent1_400</color>
|
||||||
<color name="m3_primary_500">@android:color/system_accent1_500</color>
|
<color name="m3_accent1_500">@android:color/system_accent1_500</color>
|
||||||
<color name="m3_primary_600">@android:color/system_accent1_600</color>
|
<color name="m3_accent1_600">@android:color/system_accent1_600</color>
|
||||||
<color name="m3_primary_700">@android:color/system_accent1_700</color>
|
<color name="m3_accent1_700">@android:color/system_accent1_700</color>
|
||||||
<color name="m3_primary_800">@android:color/system_accent1_800</color>
|
<color name="m3_accent1_800">@android:color/system_accent1_800</color>
|
||||||
<color name="m3_primary_900">@android:color/system_accent1_900</color>
|
<color name="m3_accent1_900">@android:color/system_accent1_900</color>
|
||||||
|
|
||||||
|
<color name="m3_neutral2_900">@android:color/system_neutral2_900</color>
|
||||||
|
<color name="m3_neutral2_800t">@android:color/system_neutral2_800</color>
|
||||||
|
<color name="m3_neutral2_800">@android:color/system_neutral2_800</color>
|
||||||
|
<color name="m3_neutral2_700">@android:color/system_neutral2_700</color>
|
||||||
|
<color name="m3_neutral2_600">@android:color/system_neutral2_600</color>
|
||||||
|
<color name="m3_neutral2_500">@android:color/system_neutral2_500</color>
|
||||||
|
<color name="m3_neutral2_400">@android:color/system_neutral2_400</color>
|
||||||
|
<color name="m3_neutral2_300">@android:color/system_neutral2_300</color>
|
||||||
|
<color name="m3_neutral2_200">@android:color/system_neutral2_200</color>
|
||||||
|
<color name="m3_neutral2_100">@android:color/system_neutral2_100</color>
|
||||||
|
<color name="m3_neutral2_50t">@android:color/system_neutral2_50</color>
|
||||||
|
<color name="m3_neutral2_50">@android:color/system_neutral2_50</color>
|
||||||
|
<color name="m3_neutral2_25">@android:color/system_neutral2_10</color>
|
||||||
|
|
||||||
|
<color name="m3_accent2_25">@android:color/system_accent2_10</color>
|
||||||
|
<color name="m3_accent2_50">@android:color/system_accent2_50</color>
|
||||||
|
<color name="m3_accent2_100">@android:color/system_accent2_100</color>
|
||||||
|
<color name="m3_accent2_200">@android:color/system_accent2_200</color>
|
||||||
|
<color name="m3_accent2_300">@android:color/system_accent2_300</color>
|
||||||
|
<color name="m3_accent2_400">@android:color/system_accent2_400</color>
|
||||||
|
<color name="m3_accent2_500">@android:color/system_accent2_500</color>
|
||||||
|
<color name="m3_accent2_600">@android:color/system_accent2_600</color>
|
||||||
|
<color name="m3_accent2_700">@android:color/system_accent2_700</color>
|
||||||
|
<color name="m3_accent2_800">@android:color/system_accent2_800</color>
|
||||||
|
<color name="m3_accent2_900">@android:color/system_accent2_900</color>
|
||||||
|
|
||||||
<!-- light theme -->
|
<!-- light theme -->
|
||||||
<color name="m3_sys_light_primary">@android:color/system_accent1_600</color>
|
<color name="m3_sys_light_primary">@android:color/system_accent1_600</color>
|
||||||
|
|||||||
@@ -106,4 +106,42 @@
|
|||||||
<attr name="colorGray800" format="color" />
|
<attr name="colorGray800" format="color" />
|
||||||
<attr name="colorGray800t" format="color" />
|
<attr name="colorGray800t" format="color" />
|
||||||
<attr name="colorGray900" format="color" />
|
<attr name="colorGray900" format="color" />
|
||||||
|
|
||||||
|
<attr name="colorSecondary25" format="color" />
|
||||||
|
<attr name="colorSecondary50" format="color" />
|
||||||
|
<attr name="colorSecondary100" format="color" />
|
||||||
|
<attr name="colorSecondary200" format="color" />
|
||||||
|
<attr name="colorSecondary300" format="color" />
|
||||||
|
<attr name="colorSecondary400" format="color" />
|
||||||
|
<attr name="colorSecondary500" format="color" />
|
||||||
|
<attr name="colorSecondary600" format="color" />
|
||||||
|
<attr name="colorSecondary700" format="color" />
|
||||||
|
<attr name="colorSecondary800" format="color" />
|
||||||
|
<attr name="colorSecondary900" format="color" />
|
||||||
|
|
||||||
|
<attr name="colorTertiary25" format="color" />
|
||||||
|
<attr name="colorTertiary50" format="color" />
|
||||||
|
<attr name="colorTertiary100" format="color" />
|
||||||
|
<attr name="colorTertiary200" format="color" />
|
||||||
|
<attr name="colorTertiary300" format="color" />
|
||||||
|
<attr name="colorTertiary400" format="color" />
|
||||||
|
<attr name="colorTertiary500" format="color" />
|
||||||
|
<attr name="colorTertiary600" format="color" />
|
||||||
|
<attr name="colorTertiary700" format="color" />
|
||||||
|
<attr name="colorTertiary800" format="color" />
|
||||||
|
<attr name="colorTertiary900" format="color" />
|
||||||
|
|
||||||
|
<attr name="colorNeutral25" format="color" />
|
||||||
|
<attr name="colorNeutral50" format="color" />
|
||||||
|
<attr name="colorNeutral50t" format="color" />
|
||||||
|
<attr name="colorNeutral100" format="color" />
|
||||||
|
<attr name="colorNeutral200" format="color" />
|
||||||
|
<attr name="colorNeutral300" format="color" />
|
||||||
|
<attr name="colorNeutral400" format="color" />
|
||||||
|
<attr name="colorNeutral500" format="color" />
|
||||||
|
<attr name="colorNeutral600" format="color" />
|
||||||
|
<attr name="colorNeutral700" format="color" />
|
||||||
|
<attr name="colorNeutral800" format="color" />
|
||||||
|
<attr name="colorNeutral800t" format="color" />
|
||||||
|
<attr name="colorNeutral900" format="color" />
|
||||||
</resources>
|
</resources>
|
||||||
@@ -103,31 +103,69 @@
|
|||||||
<!-- M3 dynamic colors -->
|
<!-- M3 dynamic colors -->
|
||||||
<color name="m3_navigation_bar_bg">@color/gray_50</color>
|
<color name="m3_navigation_bar_bg">@color/gray_50</color>
|
||||||
|
|
||||||
<color name="m3_gray_900">@color/gray_900</color>
|
<color name="m3_neutral1_900">@color/gray_900</color>
|
||||||
<color name="m3_gray_800t">@color/gray_800t</color>
|
<color name="m3_neutral1_800t">@color/gray_800t</color>
|
||||||
<color name="m3_gray_800">@color/gray_800</color>
|
<color name="m3_neutral1_800">@color/gray_800</color>
|
||||||
<color name="m3_gray_700">@color/gray_700</color>
|
<color name="m3_neutral1_700">@color/gray_700</color>
|
||||||
<color name="m3_gray_600">@color/gray_600</color>
|
<color name="m3_neutral1_600">@color/gray_600</color>
|
||||||
<color name="m3_gray_500">@color/gray_500</color>
|
<color name="m3_neutral1_500">@color/gray_500</color>
|
||||||
<color name="m3_gray_400">@color/gray_400</color>
|
<color name="m3_neutral1_400">@color/gray_400</color>
|
||||||
<color name="m3_gray_300">@color/gray_300</color>
|
<color name="m3_neutral1_300">@color/gray_300</color>
|
||||||
<color name="m3_gray_200">@color/gray_200</color>
|
<color name="m3_neutral1_200">@color/gray_200</color>
|
||||||
<color name="m3_gray_100">@color/gray_100</color>
|
<color name="m3_neutral1_100">@color/gray_100</color>
|
||||||
<color name="m3_gray_50t">@color/gray_50t</color>
|
<color name="m3_neutral1_50t">@color/gray_50t</color>
|
||||||
<color name="m3_gray_50">@color/gray_50</color>
|
<color name="m3_neutral1_50">@color/gray_50</color>
|
||||||
<color name="m3_gray_25">@color/gray_25</color>
|
<color name="m3_neutral1_25">@color/gray_25</color>
|
||||||
|
|
||||||
<color name="m3_primary_25">@color/primary_25</color>
|
<color name="m3_neutral2_900">@color/gray_900</color>
|
||||||
<color name="m3_primary_50">@color/primary_50</color>
|
<color name="m3_neutral2_800t">@color/gray_800t</color>
|
||||||
<color name="m3_primary_100">@color/primary_100</color>
|
<color name="m3_neutral2_800">@color/gray_800</color>
|
||||||
<color name="m3_primary_200">@color/primary_200</color>
|
<color name="m3_neutral2_700">@color/gray_700</color>
|
||||||
<color name="m3_primary_300">@color/primary_300</color>
|
<color name="m3_neutral2_600">@color/gray_600</color>
|
||||||
<color name="m3_primary_400">@color/primary_400</color>
|
<color name="m3_neutral2_500">@color/gray_500</color>
|
||||||
<color name="m3_primary_500">@color/primary_500</color>
|
<color name="m3_neutral2_400">@color/gray_400</color>
|
||||||
<color name="m3_primary_600">@color/primary_600</color>
|
<color name="m3_neutral2_300">@color/gray_300</color>
|
||||||
<color name="m3_primary_700">@color/primary_700</color>
|
<color name="m3_neutral2_200">@color/gray_200</color>
|
||||||
<color name="m3_primary_800">@color/primary_800</color>
|
<color name="m3_neutral2_100">@color/gray_100</color>
|
||||||
<color name="m3_primary_900">@color/primary_900</color>
|
<color name="m3_neutral2_50t">@color/gray_50t</color>
|
||||||
|
<color name="m3_neutral2_50">@color/gray_50</color>
|
||||||
|
<color name="m3_neutral2_25">@color/gray_25</color>
|
||||||
|
|
||||||
|
<color name="m3_accent1_25">@color/primary_25</color>
|
||||||
|
<color name="m3_accent1_50">@color/primary_50</color>
|
||||||
|
<color name="m3_accent1_100">@color/primary_100</color>
|
||||||
|
<color name="m3_accent1_200">@color/primary_200</color>
|
||||||
|
<color name="m3_accent1_300">@color/primary_300</color>
|
||||||
|
<color name="m3_accent1_400">@color/primary_400</color>
|
||||||
|
<color name="m3_accent1_500">@color/primary_500</color>
|
||||||
|
<color name="m3_accent1_600">@color/primary_600</color>
|
||||||
|
<color name="m3_accent1_700">@color/primary_700</color>
|
||||||
|
<color name="m3_accent1_800">@color/primary_800</color>
|
||||||
|
<color name="m3_accent1_900">@color/primary_900</color>
|
||||||
|
|
||||||
|
<color name="m3_accent2_25">@color/primary_25</color>
|
||||||
|
<color name="m3_accent2_50">@color/primary_50</color>
|
||||||
|
<color name="m3_accent2_100">@color/primary_100</color>
|
||||||
|
<color name="m3_accent2_200">@color/primary_200</color>
|
||||||
|
<color name="m3_accent2_300">@color/primary_300</color>
|
||||||
|
<color name="m3_accent2_400">@color/primary_400</color>
|
||||||
|
<color name="m3_accent2_500">@color/primary_500</color>
|
||||||
|
<color name="m3_accent2_600">@color/primary_600</color>
|
||||||
|
<color name="m3_accent2_700">@color/primary_700</color>
|
||||||
|
<color name="m3_accent2_800">@color/primary_800</color>
|
||||||
|
<color name="m3_accent2_900">@color/primary_900</color>
|
||||||
|
|
||||||
|
<color name="m3_accent3_25">@color/primary_25</color>
|
||||||
|
<color name="m3_accent3_50">@color/primary_50</color>
|
||||||
|
<color name="m3_accent3_100">@color/primary_100</color>
|
||||||
|
<color name="m3_accent3_200">@color/primary_200</color>
|
||||||
|
<color name="m3_accent3_300">@color/primary_300</color>
|
||||||
|
<color name="m3_accent3_400">@color/primary_400</color>
|
||||||
|
<color name="m3_accent3_500">@color/primary_500</color>
|
||||||
|
<color name="m3_accent3_600">@color/primary_600</color>
|
||||||
|
<color name="m3_accent3_700">@color/primary_700</color>
|
||||||
|
<color name="m3_accent3_800">@color/primary_800</color>
|
||||||
|
<color name="m3_accent3_900">@color/primary_900</color>
|
||||||
|
|
||||||
<!-- light theme -->
|
<!-- light theme -->
|
||||||
<color name="m3_sys_light_primary">#6750A4</color>
|
<color name="m3_sys_light_primary">#6750A4</color>
|
||||||
|
|||||||
@@ -26,34 +26,115 @@
|
|||||||
<item name="colorGray50t">@color/gray_50t</item>
|
<item name="colorGray50t">@color/gray_50t</item>
|
||||||
<item name="colorGray50">@color/gray_50</item>
|
<item name="colorGray50">@color/gray_50</item>
|
||||||
<item name="colorGray25">@color/gray_25</item>
|
<item name="colorGray25">@color/gray_25</item>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
custom themes generally don't have secondary/tertiary accent colors -
|
||||||
|
falling back to primary colors
|
||||||
|
-->
|
||||||
|
|
||||||
|
<item name="colorSecondary25">@color/primary_25</item>
|
||||||
|
<item name="colorSecondary50">@color/primary_50</item>
|
||||||
|
<item name="colorSecondary100">@color/primary_100</item>
|
||||||
|
<item name="colorSecondary200">@color/primary_200</item>
|
||||||
|
<item name="colorSecondary300">@color/primary_300</item>
|
||||||
|
<item name="colorSecondary400">@color/primary_400</item>
|
||||||
|
<item name="colorSecondary500">@color/primary_500</item>
|
||||||
|
<item name="colorSecondary600">@color/primary_600</item>
|
||||||
|
<item name="colorSecondary700">@color/primary_700</item>
|
||||||
|
<item name="colorSecondary800">@color/primary_800</item>
|
||||||
|
<item name="colorSecondary900">@color/primary_900</item>
|
||||||
|
|
||||||
|
<item name="colorTertiary25">@color/primary_25</item>
|
||||||
|
<item name="colorTertiary50">@color/primary_50</item>
|
||||||
|
<item name="colorTertiary100">@color/primary_100</item>
|
||||||
|
<item name="colorTertiary200">@color/primary_200</item>
|
||||||
|
<item name="colorTertiary300">@color/primary_300</item>
|
||||||
|
<item name="colorTertiary400">@color/primary_400</item>
|
||||||
|
<item name="colorTertiary500">@color/primary_500</item>
|
||||||
|
<item name="colorTertiary600">@color/primary_600</item>
|
||||||
|
<item name="colorTertiary700">@color/primary_700</item>
|
||||||
|
<item name="colorTertiary800">@color/primary_800</item>
|
||||||
|
<item name="colorTertiary900">@color/primary_900</item>
|
||||||
|
|
||||||
|
<item name="colorNeutral900">@color/gray_900</item>
|
||||||
|
<item name="colorNeutral800t">@color/gray_800t</item>
|
||||||
|
<item name="colorNeutral800">@color/gray_800</item>
|
||||||
|
<item name="colorNeutral700">@color/gray_700</item>
|
||||||
|
<item name="colorNeutral600">@color/gray_600</item>
|
||||||
|
<item name="colorNeutral500">@color/gray_500</item>
|
||||||
|
<item name="colorNeutral400">@color/gray_400</item>
|
||||||
|
<item name="colorNeutral300">@color/gray_300</item>
|
||||||
|
<item name="colorNeutral200">@color/gray_200</item>
|
||||||
|
<item name="colorNeutral100">@color/gray_100</item>
|
||||||
|
<item name="colorNeutral50t">@color/gray_50t</item>
|
||||||
|
<item name="colorNeutral50">@color/gray_50</item>
|
||||||
|
<item name="colorNeutral25">@color/gray_25</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="ColorPalette.Material3">
|
<style name="ColorPalette.Material3">
|
||||||
<item name="colorPrimary25">@color/m3_primary_25</item>
|
<item name="colorPrimary25">@color/m3_accent1_25</item>
|
||||||
<item name="colorPrimary50">@color/m3_primary_50</item>
|
<item name="colorPrimary50">@color/m3_accent1_50</item>
|
||||||
<item name="colorPrimary100">@color/m3_primary_100</item>
|
<item name="colorPrimary100">@color/m3_accent1_100</item>
|
||||||
<item name="colorPrimary200">@color/m3_primary_200</item>
|
<item name="colorPrimary200">@color/m3_accent1_200</item>
|
||||||
<item name="colorPrimary300">@color/m3_primary_300</item>
|
<item name="colorPrimary300">@color/m3_accent1_300</item>
|
||||||
<item name="colorPrimary400">@color/m3_primary_400</item>
|
<item name="colorPrimary400">@color/m3_accent1_400</item>
|
||||||
<item name="colorPrimary500">@color/m3_primary_500</item>
|
<item name="colorPrimary500">@color/m3_accent1_500</item>
|
||||||
<item name="colorPrimary600">@color/m3_primary_600</item>
|
<item name="colorPrimary600">@color/m3_accent1_600</item>
|
||||||
<item name="colorPrimary700">@color/m3_primary_700</item>
|
<item name="colorPrimary700">@color/m3_accent1_700</item>
|
||||||
<item name="colorPrimary800">@color/m3_primary_800</item>
|
<item name="colorPrimary800">@color/m3_accent1_800</item>
|
||||||
<item name="colorPrimary900">@color/m3_primary_900</item>
|
<item name="colorPrimary900">@color/m3_accent1_900</item>
|
||||||
|
|
||||||
<item name="colorGray900">@color/m3_gray_900</item>
|
<item name="colorSecondary25">@color/m3_accent2_25</item>
|
||||||
<item name="colorGray800t">@color/m3_gray_800t</item>
|
<item name="colorSecondary50">@color/m3_accent2_50</item>
|
||||||
<item name="colorGray800">@color/m3_gray_800</item>
|
<item name="colorSecondary100">@color/m3_accent2_100</item>
|
||||||
<item name="colorGray700">@color/m3_gray_700</item>
|
<item name="colorSecondary200">@color/m3_accent2_200</item>
|
||||||
<item name="colorGray600">@color/m3_gray_600</item>
|
<item name="colorSecondary300">@color/m3_accent2_300</item>
|
||||||
<item name="colorGray500">@color/m3_gray_500</item>
|
<item name="colorSecondary400">@color/m3_accent2_400</item>
|
||||||
<item name="colorGray400">@color/m3_gray_400</item>
|
<item name="colorSecondary500">@color/m3_accent2_500</item>
|
||||||
<item name="colorGray300">@color/m3_gray_300</item>
|
<item name="colorSecondary600">@color/m3_accent2_600</item>
|
||||||
<item name="colorGray200">@color/m3_gray_200</item>
|
<item name="colorSecondary700">@color/m3_accent2_700</item>
|
||||||
<item name="colorGray100">@color/m3_gray_100</item>
|
<item name="colorSecondary800">@color/m3_accent2_800</item>
|
||||||
<item name="colorGray50t">@color/m3_gray_50t</item>
|
<item name="colorSecondary900">@color/m3_accent2_900</item>
|
||||||
<item name="colorGray50">@color/m3_gray_50</item>
|
|
||||||
<item name="colorGray25">@color/m3_gray_25</item>
|
<item name="colorTertiary25">@color/m3_accent3_25</item>
|
||||||
|
<item name="colorTertiary50">@color/m3_accent3_50</item>
|
||||||
|
<item name="colorTertiary100">@color/m3_accent3_100</item>
|
||||||
|
<item name="colorTertiary200">@color/m3_accent3_200</item>
|
||||||
|
<item name="colorTertiary300">@color/m3_accent3_300</item>
|
||||||
|
<item name="colorTertiary400">@color/m3_accent3_400</item>
|
||||||
|
<item name="colorTertiary500">@color/m3_accent3_500</item>
|
||||||
|
<item name="colorTertiary600">@color/m3_accent3_600</item>
|
||||||
|
<item name="colorTertiary700">@color/m3_accent3_700</item>
|
||||||
|
<item name="colorTertiary800">@color/m3_accent3_800</item>
|
||||||
|
<item name="colorTertiary900">@color/m3_accent3_900</item>
|
||||||
|
|
||||||
|
<item name="colorGray900">@color/m3_neutral1_900</item>
|
||||||
|
<item name="colorGray800t">@color/m3_neutral1_800t</item>
|
||||||
|
<item name="colorGray800">@color/m3_neutral1_800</item>
|
||||||
|
<item name="colorGray700">@color/m3_neutral1_700</item>
|
||||||
|
<item name="colorGray600">@color/m3_neutral1_600</item>
|
||||||
|
<item name="colorGray500">@color/m3_neutral1_500</item>
|
||||||
|
<item name="colorGray400">@color/m3_neutral1_400</item>
|
||||||
|
<item name="colorGray300">@color/m3_neutral1_300</item>
|
||||||
|
<item name="colorGray200">@color/m3_neutral1_200</item>
|
||||||
|
<item name="colorGray100">@color/m3_neutral1_100</item>
|
||||||
|
<item name="colorGray50t">@color/m3_neutral1_50t</item>
|
||||||
|
<item name="colorGray50">@color/m3_neutral1_50</item>
|
||||||
|
<item name="colorGray25">@color/m3_neutral1_25</item>
|
||||||
|
|
||||||
|
<item name="colorNeutral900">@color/m3_neutral2_900</item>
|
||||||
|
<item name="colorNeutral800t">@color/m3_neutral2_800t</item>
|
||||||
|
<item name="colorNeutral800">@color/m3_neutral2_800</item>
|
||||||
|
<item name="colorNeutral700">@color/m3_neutral2_700</item>
|
||||||
|
<item name="colorNeutral600">@color/m3_neutral2_600</item>
|
||||||
|
<item name="colorNeutral500">@color/m3_neutral2_500</item>
|
||||||
|
<item name="colorNeutral400">@color/m3_neutral2_400</item>
|
||||||
|
<item name="colorNeutral300">@color/m3_neutral2_300</item>
|
||||||
|
<item name="colorNeutral200">@color/m3_neutral2_200</item>
|
||||||
|
<item name="colorNeutral100">@color/m3_neutral2_100</item>
|
||||||
|
<item name="colorNeutral50t">@color/m3_neutral2_50t</item>
|
||||||
|
<item name="colorNeutral50">@color/m3_neutral2_50</item>
|
||||||
|
<item name="colorNeutral25">@color/m3_neutral2_25</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="ColorPalette.Material3.Dark">
|
<style name="ColorPalette.Material3.Dark">
|
||||||
|
|||||||
@@ -452,4 +452,6 @@
|
|||||||
<string name="welcome_paragraph1">Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together.</string>
|
<string name="welcome_paragraph1">Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together.</string>
|
||||||
<string name="what_are_servers">What are servers?</string>
|
<string name="what_are_servers">What are servers?</string>
|
||||||
<string name="welcome_paragraph2"><![CDATA[Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server.]]></string>
|
<string name="welcome_paragraph2"><![CDATA[Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server.]]></string>
|
||||||
|
<string name="log_out_all_accounts">Log out of all accounts</string>
|
||||||
|
<string name="confirm_log_out_all_accounts">Log out of all accounts?</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -288,4 +288,8 @@
|
|||||||
<string name="sk_settings_content_types_explanation">Allows setting a content type like Markdown when creating a post. Keep in mind that not all instances support this.</string>
|
<string name="sk_settings_content_types_explanation">Allows setting a content type like Markdown when creating a post. Keep in mind that not all instances support this.</string>
|
||||||
<string name="sk_settings_default_content_type">Default content type</string>
|
<string name="sk_settings_default_content_type">Default content type</string>
|
||||||
<string name="sk_settings_default_content_type_explanation">This lets you have a content type be pre-selected when creating new posts, overriding the value set in “Posting preferences”.</string>
|
<string name="sk_settings_default_content_type_explanation">This lets you have a content type be pre-selected when creating new posts, overriding the value set in “Posting preferences”.</string>
|
||||||
|
<string name="sk_instance_info_unavailable">Instance info temporarily unavailable</string>
|
||||||
|
<string name="sk_open_in_app">Open in app</string>
|
||||||
|
<string name="sk_external_share_title">Share with account</string>
|
||||||
|
<string name="sk_external_share_or_open_title">Share or open with account</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<style name="TransparentDialog" parent="android:Theme.Dialog">
|
||||||
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowIsFloating">true</item>
|
||||||
|
<item name="android:backgroundDimEnabled">false</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Mastodon.Light" parent="Theme.AppKit.Light">
|
<style name="Theme.Mastodon.Light" parent="Theme.AppKit.Light">
|
||||||
<!-- needed to disable scrim on API 29+ -->
|
<!-- needed to disable scrim on API 29+ -->
|
||||||
<item name="android:enforceNavigationBarContrast" tools:ignore="NewApi">false</item>
|
<item name="android:enforceNavigationBarContrast" tools:ignore="NewApi">false</item>
|
||||||
@@ -53,29 +63,29 @@
|
|||||||
<item name="android:actionOverflowMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
|
<item name="android:actionOverflowMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
|
||||||
|
|
||||||
<!-- M3 colors -->
|
<!-- M3 colors -->
|
||||||
<item name="colorM3Primary">@color/m3_sys_light_primary</item>
|
<item name="colorM3Primary">?colorPrimary600</item>
|
||||||
<item name="colorM3OnPrimary">@color/m3_sys_light_on_primary</item>
|
<item name="colorM3OnPrimary">@color/white</item>
|
||||||
<item name="colorM3PrimaryContainer">@color/m3_sys_light_primary_container</item>
|
<item name="colorM3PrimaryContainer">?colorPrimary100</item>
|
||||||
<item name="colorM3OnPrimaryContainer">@color/m3_sys_light_on_primary_container</item>
|
<item name="colorM3OnPrimaryContainer">?colorPrimary900</item>
|
||||||
<item name="colorM3Secondary">@color/m3_sys_light_secondary</item>
|
<item name="colorM3Secondary">?colorSecondary600</item>
|
||||||
<item name="colorM3OnSecondary">@color/m3_sys_light_on_secondary</item>
|
<item name="colorM3OnSecondary">@color/white</item>
|
||||||
<item name="colorM3SecondaryContainer">@color/m3_sys_light_secondary_container</item>
|
<item name="colorM3SecondaryContainer">?colorSecondary100</item>
|
||||||
<item name="colorM3OnSecondaryContainer">@color/m3_sys_light_on_secondary_container</item>
|
<item name="colorM3OnSecondaryContainer">?colorSecondary900</item>
|
||||||
<item name="colorM3Tertiary">@color/m3_sys_light_tertiary</item>
|
<item name="colorM3Tertiary">?colorTertiary600</item>
|
||||||
<item name="colorM3OnTertiary">@color/m3_sys_light_on_tertiary</item>
|
<item name="colorM3OnTertiary">@color/white</item>
|
||||||
<item name="colorM3TertiaryContainer">@color/m3_sys_light_tertiary_container</item>
|
<item name="colorM3TertiaryContainer">?colorTertiary100</item>
|
||||||
<item name="colorM3OnTertiaryContainer">@color/m3_sys_light_on_tertiary_container</item>
|
<item name="colorM3OnTertiaryContainer">?colorTertiary900</item>
|
||||||
<item name="colorM3Background">@color/m3_sys_light_background</item>
|
<item name="colorM3Background">?colorGray25</item>
|
||||||
<item name="colorM3OnBackground">@color/m3_sys_light_on_background</item>
|
<item name="colorM3OnBackground">?colorGray900</item>
|
||||||
<item name="colorM3Surface">@color/m3_sys_light_surface</item>
|
<item name="colorM3Surface">?colorGray25</item>
|
||||||
<item name="colorM3OnSurface">@color/m3_sys_light_on_surface</item>
|
<item name="colorM3OnSurface">?colorGray900</item>
|
||||||
<item name="colorM3SurfaceVariant">@color/m3_sys_light_surface_variant</item>
|
<item name="colorM3SurfaceVariant">?colorNeutral100</item>
|
||||||
<item name="colorM3OnSurfaceVariant">@color/m3_sys_light_on_surface_variant</item>
|
<item name="colorM3OnSurfaceVariant">?colorNeutral700</item>
|
||||||
<item name="colorM3Outline">@color/m3_sys_light_outline</item>
|
<item name="colorM3Outline">?colorNeutral500</item>
|
||||||
<item name="colorM3DisabledBackground">#1F1F1F1F</item>
|
<item name="colorM3DisabledBackground">#1F1F1F1F</item>
|
||||||
<item name="colorM3PressedOverlay">@color/m3_sys_light_on_primary</item>
|
<item name="colorM3PressedOverlay">@color/white</item>
|
||||||
<item name="colorM3Error">#B3261E</item>
|
<item name="colorM3Error">#B3261E</item>
|
||||||
<item name="colorM3OnError">#FFF</item>
|
<item name="colorM3OnError">@color/white</item>
|
||||||
<item name="colorM3ErrorContainer">#F9DEDC</item>
|
<item name="colorM3ErrorContainer">#F9DEDC</item>
|
||||||
<item name="colorM3OnErrorContainer">#410E0B</item>
|
<item name="colorM3OnErrorContainer">#410E0B</item>
|
||||||
|
|
||||||
@@ -153,27 +163,27 @@
|
|||||||
<item name="android:actionOverflowMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
|
<item name="android:actionOverflowMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
|
||||||
|
|
||||||
<!-- M3 colors -->
|
<!-- M3 colors -->
|
||||||
<item name="colorM3Primary">@color/m3_sys_dark_primary</item>
|
<item name="colorM3Primary">?colorPrimary200</item>
|
||||||
<item name="colorM3OnPrimary">@color/m3_sys_dark_on_primary</item>
|
<item name="colorM3OnPrimary">?colorPrimary800</item>
|
||||||
<item name="colorM3PrimaryContainer">@color/m3_sys_dark_primary_container</item>
|
<item name="colorM3PrimaryContainer">?colorPrimary700</item>
|
||||||
<item name="colorM3OnPrimaryContainer">@color/m3_sys_dark_on_primary_container</item>
|
<item name="colorM3OnPrimaryContainer">?colorPrimary100</item>
|
||||||
<item name="colorM3Secondary">@color/m3_sys_dark_secondary</item>
|
<item name="colorM3Secondary">?colorSecondary200</item>
|
||||||
<item name="colorM3OnSecondary">@color/m3_sys_dark_on_secondary</item>
|
<item name="colorM3OnSecondary">?colorSecondary800</item>
|
||||||
<item name="colorM3SecondaryContainer">@color/m3_sys_dark_secondary_container</item>
|
<item name="colorM3SecondaryContainer">?colorSecondary700</item>
|
||||||
<item name="colorM3OnSecondaryContainer">@color/m3_sys_dark_on_secondary_container</item>
|
<item name="colorM3OnSecondaryContainer">?colorSecondary100</item>
|
||||||
<item name="colorM3Tertiary">@color/m3_sys_dark_tertiary</item>
|
<item name="colorM3Tertiary">?colorTertiary200</item>
|
||||||
<item name="colorM3OnTertiary">@color/m3_sys_dark_on_tertiary</item>
|
<item name="colorM3OnTertiary">?colorTertiary800</item>
|
||||||
<item name="colorM3TertiaryContainer">@color/m3_sys_dark_tertiary_container</item>
|
<item name="colorM3TertiaryContainer">?colorTertiary700</item>
|
||||||
<item name="colorM3OnTertiaryContainer">@color/m3_sys_dark_on_tertiary_container</item>
|
<item name="colorM3OnTertiaryContainer">?colorTertiary100</item>
|
||||||
<item name="colorM3Background">@color/m3_sys_dark_background</item>
|
<item name="colorM3Background">?colorGray900</item>
|
||||||
<item name="colorM3OnBackground">@color/m3_sys_dark_on_background</item>
|
<item name="colorM3OnBackground">?colorGray100</item>
|
||||||
<item name="colorM3Surface">@color/m3_sys_dark_surface</item>
|
<item name="colorM3Surface">?colorGray900</item>
|
||||||
<item name="colorM3OnSurface">@color/m3_sys_dark_on_surface</item>
|
<item name="colorM3OnSurface">?colorGray100</item>
|
||||||
<item name="colorM3SurfaceVariant">@color/m3_sys_dark_surface_variant</item>
|
<item name="colorM3SurfaceVariant">?colorNeutral700</item>
|
||||||
<item name="colorM3OnSurfaceVariant">@color/m3_sys_dark_on_surface_variant</item>
|
<item name="colorM3OnSurfaceVariant">?colorNeutral200</item>
|
||||||
<item name="colorM3Outline">@color/m3_sys_dark_outline</item>
|
<item name="colorM3Outline">?colorNeutral400</item>
|
||||||
<item name="colorM3DisabledBackground">#1FE3E3E3</item>
|
<item name="colorM3DisabledBackground">#1FE3E3E3</item>
|
||||||
<item name="colorM3PressedOverlay">@color/m3_sys_dark_primary</item>
|
<item name="colorM3PressedOverlay">?colorPrimary200</item>
|
||||||
<item name="colorM3Error">#F2B8B5</item>
|
<item name="colorM3Error">#F2B8B5</item>
|
||||||
<item name="colorM3OnError">#601410</item>
|
<item name="colorM3OnError">#601410</item>
|
||||||
<item name="colorM3ErrorContainer">#8C1D18</item>
|
<item name="colorM3ErrorContainer">#8C1D18</item>
|
||||||
@@ -221,7 +231,8 @@
|
|||||||
<item name="colorComposeButton">?android:colorAccent</item>
|
<item name="colorComposeButton">?android:colorAccent</item>
|
||||||
<item name="colorComposeButtonBackground">?colorGray900</item>
|
<item name="colorComposeButtonBackground">?colorGray900</item>
|
||||||
|
|
||||||
<item name="colorM3Background">#000</item>
|
<item name="colorM3Background">@color/black</item>
|
||||||
|
<item name="colorM3Surface">@color/black</item>
|
||||||
<!-- <item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">?colorGray900</item>-->
|
<!-- <item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">?colorGray900</item>-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -447,6 +458,11 @@
|
|||||||
<item name="android:gravity">center_vertical</item>
|
<item name="android:gravity">center_vertical</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="sheet_title">
|
||||||
|
<item name="android:textSize">20sp</item>
|
||||||
|
<item name="android:gravity">center_vertical</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="m3_body_large">
|
<style name="m3_body_large">
|
||||||
<item name="android:textSize">16sp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
<item name="android:textColor">?android:textColorPrimary</item>
|
<item name="android:textColor">?android:textColorPrimary</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user