Compare commits

...

28 Commits

Author SHA1 Message Date
Samuel Kaiser
86d2312615 Update README.md 2022-05-22 02:07:07 +02:00
sk
d1083c331b Merge branch 'feature/bookmarks' into fork 2022-05-22 02:04:08 +02:00
sk
ed7242217a add missing icon 2022-05-22 02:03:54 +02:00
sk
8fddaa8c82 implement bookmarks list!! 2022-05-22 02:03:29 +02:00
sk
00affe6e3e update readme 2022-05-21 23:38:56 +02:00
sk
f21b647ee0 bump version 2022-05-21 23:35:10 +02:00
sk
2a628a3791 Merge branch 'feature/back-returns-home' into fork 2022-05-21 23:34:18 +02:00
sk
ecd568503d make back button return home before exiting 2022-05-21 23:33:53 +02:00
sk
f9d0632a85 add missing files 2022-05-21 19:42:29 +02:00
sk
11905513b7 add missing icons 2022-05-21 19:40:49 +02:00
sk
9c89abf1c4 implement bookmark button 2022-05-21 19:27:44 +02:00
sk
4d950e43ac update readme 2022-05-21 18:59:13 +02:00
sk
99405f307d bump version 2022-05-21 18:49:59 +02:00
sk
f1bfe05263 Merge branch 'feature/always-preserve-cw' into fork 2022-05-21 18:49:07 +02:00
sk
0f223159c0 always preserve cw when replying 2022-05-21 18:48:48 +02:00
sk
ad9518e87c re-add deleted strings 2022-05-21 18:08:14 +02:00
sk
1c16cfb09e bump version 2022-05-21 18:05:01 +02:00
sk
d4a4b10017 Merge branch 'feature/compose-image-description-full-image' into fork 2022-05-21 18:03:29 +02:00
sk
74ae5bd04e change app name 2022-05-21 18:03:15 +02:00
sk
9638cf079f set image view height to wrap_content 2022-05-21 17:48:53 +02:00
sk
a6d161c1b4 minor code style change
for grishka's code style must prevail
2022-05-21 17:42:40 +02:00
sk
1136e40eb4 obey image max width 2022-05-21 17:39:28 +02:00
sk
98de3a2984 don't crop image when composing alt text 2022-05-21 17:27:31 +02:00
Grishka
080a320e12 Make the app name non-translatable 2022-05-17 18:47:11 +03:00
sk
b08415ca8f bump version 2022-05-15 20:35:10 +02:00
sk
3639c69d36 Merge branch 'master' into fork 2022-05-15 20:34:14 +02:00
Grishka
37cefcaf6d Fix #164 2022-05-15 21:13:36 +03:00
Grishka
558adc6936 Add compose shortcut
closes #131
2022-05-15 19:14:24 +03:00
26 changed files with 324 additions and 20 deletions

View File

@@ -1,18 +1,21 @@
# Forked Mastodon for Android
[![Crowdin](https://badges.crowdin.net/mastodon-for-android/localized.svg)](https://crowdin.com/project/mastodon-for-android)
This is the repository for an officially forked Android app for Mastodon.
Learn more about this app in the [blog post](https://blog.joinmastodon.org/2022/02/official-mastodon-for-android-app-is-coming-soon/).
Learn more about the official app in the [blog post](https://blog.joinmastodon.org/2022/02/official-mastodon-for-android-app-is-coming-soon/).
## Changes
* [Enable "Unlisted" as a visibility option](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted)
([Pull request](https://github.com/mastodon/mastodon-android/pull/103)) and
[set as default](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted-as-default)
* [Add "Federation" tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline)
* [Add "Federation" tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/8))
* [Add image description button and viewer](https://github.com/sk22/mastodon-android-fork/tree/feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
* [Implement pinning posts and displaying pinned posts](https://github.com/sk22/mastodon-android-fork/tree/feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
* [Display full image when adding image description](https://github.com/sk22/mastodon-android-fork/tree/feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
* [Always preserve content warnings when replying](https://github.com/sk22/mastodon-android-fork/tree/feature/always-preserve-cw) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/113))
* [Make back button return to the home tab before exiting the app](https://github.com/sk22/mastodon-android-fork/tree/feature/back-returns-home) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/118))
* [Implement a bookmark button and list](https://github.com/sk22/mastodon-android-fork/tree/feature/bookmarks) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/22))
## Building

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 31
versionCode 9
versionName '1.1.1-dev+fork.9'
versionCode 13
versionName '1.1.1+fork.13'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -9,6 +9,7 @@ import android.util.Log;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.SplashFragment;
@@ -56,6 +57,8 @@ public class MainActivity extends FragmentStackActivity{
if(intent.getBooleanExtra("fromNotification", false) && intent.hasExtra("notification")){
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
showFragmentForNotification(notification, session.getID());
}else if(intent.getBooleanExtra("compose", false)){
showCompose();
}
}
}
@@ -91,6 +94,8 @@ public class MainActivity extends FragmentStackActivity{
fragment.setArguments(args);
showFragmentClearingBackStack(fragment);
}
}else if(intent.getBooleanExtra("compose", false)){
showCompose();
}
}
@@ -115,4 +120,15 @@ public class MainActivity extends FragmentStackActivity{
fragment.setArguments(args);
showFragment(fragment);
}
private void showCompose(){
AccountSession session=AccountSessionManager.getInstance().getLastActiveAccount();
if(session==null || !session.activated)
return;
ComposeFragment compose=new ComposeFragment();
Bundle composeArgs=new Bundle();
composeArgs.putString("account", session.getID());
compose.setArguments(composeArgs);
showFragment(compose);
}
}

View File

@@ -4,6 +4,7 @@ import android.os.Looper;
import org.joinmastodon.android.E;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
@@ -18,6 +19,7 @@ public class StatusInteractionController{
private final String accountID;
private final HashMap<String, SetStatusFavorited> runningFavoriteRequests=new HashMap<>();
private final HashMap<String, SetStatusReblogged> runningReblogRequests=new HashMap<>();
private final HashMap<String, SetStatusBookmarked> runningBookmarkRequests=new HashMap<>();
public StatusInteractionController(String accountID){
this.accountID=accountID;
@@ -61,6 +63,36 @@ public class StatusInteractionController{
E.post(new StatusCountersUpdatedEvent(status));
}
public void setBookmarked(Status status, boolean bookmarked){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");
SetStatusBookmarked current=runningBookmarkRequests.remove(status.id);
if(current!=null){
current.cancel();
}
SetStatusBookmarked req=(SetStatusBookmarked) new SetStatusBookmarked(status.id, bookmarked)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Status result){
runningBookmarkRequests.remove(status.id);
E.post(new StatusCountersUpdatedEvent(result));
}
@Override
public void onError(ErrorResponse error){
runningBookmarkRequests.remove(status.id);
error.showToast(MastodonApp.context);
status.bookmarked=!bookmarked;
E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningBookmarkRequests.put(status.id, req);
status.bookmarked=bookmarked;
E.post(new StatusCountersUpdatedEvent(status));
}
public void setReblogged(Status status, boolean reblogged){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");

View File

@@ -0,0 +1,52 @@
package org.joinmastodon.android.api.requests.accounts;
import androidx.annotation.NonNull;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import okhttp3.Response;
public class GetBookmarks extends MastodonAPIRequest<List<Status>>{
private String maxId;
public GetBookmarks(String maxID, String minID, int limit){
super(HttpMethod.GET, "/bookmarks", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(minID!=null)
addQueryParameter("min_id", minID);
if(limit>0)
addQueryParameter("limit", ""+limit);
}
@Override
public void validateAndPostprocessResponse(List<Status> respObj, Response httpResponse) throws IOException {
super.validateAndPostprocessResponse(respObj, httpResponse);
// <https://mastodon.social/api/v1/bookmarks?max_id=268962>; rel="next",
// <https://mastodon.social/api/v1/bookmarks?min_id=268981>; rel="prev"
String link=httpResponse.header("link");
// parsing link header by hand; using a library would be cleaner
// (also, the functionality should be part of the max id logics and implemented in MastodonAPIRequest)
if(link==null) return;
String maxIdEq="max_id=";
for(String s : link.split(",")) {
if(s.contains("rel=\"next\"")) {
int start=s.indexOf(maxIdEq)+maxIdEq.length();
int end=s.indexOf('>');
if(start<0 || start>end) return;
this.maxId=s.substring(start, end);
}
}
}
public String getMaxId() {
return maxId;
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class SetStatusBookmarked extends MastodonAPIRequest<Status>{
public SetStatusBookmarked(String id, boolean bookmarked){
super(HttpMethod.POST, "/statuses/"+id+"/"+(bookmarked ? "bookmark" : "unbookmark"), Status.class);
setRequestBody(new Object());
}
}

View File

@@ -2,15 +2,22 @@ package org.joinmastodon.android.api.session;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import com.google.gson.JsonParseException;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
@@ -90,6 +97,7 @@ public class AccountSessionManager{
}
lastActiveAccountID=prefs.getString("lastActiveAccount", null);
MastodonAPIController.runInBackground(()->readInstanceInfo(domains));
maybeUpdateShortcuts();
}
public void addAccount(Instance instance, Token token, Account self, Application app, boolean active){
@@ -102,6 +110,7 @@ public class AccountSessionManager{
if(PushSubscriptionManager.arePushNotificationsAvailable()){
session.getPushSubscriptionManager().registerAccountForPush(null);
}
maybeUpdateShortcuts();
}
public synchronized void writeAccountsFile(){
@@ -181,6 +190,7 @@ public class AccountSessionManager{
NotificationManager nm=MastodonApp.context.getSystemService(NotificationManager.class);
nm.deleteNotificationChannelGroup(id);
}
maybeUpdateShortcuts();
}
@NonNull
@@ -395,6 +405,29 @@ public class AccountSessionManager{
writeAccountsFile();
}
private void maybeUpdateShortcuts(){
if(Build.VERSION.SDK_INT<26)
return;
ShortcutManager sm=MastodonApp.context.getSystemService(ShortcutManager.class);
if((sm.getDynamicShortcuts().isEmpty() || BuildConfig.DEBUG) && !sessions.isEmpty()){
// There are no shortcuts, but there are accounts. Add a compose shortcut.
ShortcutInfo info=new ShortcutInfo.Builder(MastodonApp.context, "compose")
.setActivity(ComponentName.createRelative(MastodonApp.context, MainActivity.class.getName()))
.setShortLabel(MastodonApp.context.getString(R.string.new_post))
.setIcon(Icon.createWithResource(MastodonApp.context, R.mipmap.ic_shortcut_compose))
.setIntent(new Intent(MastodonApp.context, MainActivity.class)
.setAction(Intent.ACTION_MAIN)
.putExtra("compose", true))
.build();
sm.setDynamicShortcuts(Collections.singletonList(info));
}else if(sessions.isEmpty()){
// There are shortcuts, but no accounts. Disable existing shortcuts.
sm.disableShortcuts(Collections.singletonList("compose"), MastodonApp.context.getString(R.string.err_not_logged_in));
}else{
sm.enableShortcuts(Collections.singletonList("compose"));
}
}
private static class SessionsStorageWrapper{
public List<AccountSession> accounts;
}

View File

@@ -0,0 +1,53 @@
package org.joinmastodon.android.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetBookmarks;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Status;
import java.util.List;
import me.grishka.appkit.api.SimpleCallback;
public class BookmarksListFragment extends StatusListFragment{
private String accountID;
private Account self;
private String lastMaxId=null;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
self=session.self;
setTitle(R.string.bookmarks);
}
@Override
protected void onShown(){
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}
@Override
protected void doLoadData(int offset, int count) {
GetBookmarks b=new GetBookmarks(offset>0 ? lastMaxId : null, null, count);
currentRequest=b.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
onDataLoaded(result, b.getMaxId()!=null);
lastMaxId=b.getMaxId();
}
})
.exec(accountID);
}
}

View File

@@ -453,7 +453,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
if(savedInstanceState==null){
mainEditText.setText(initialText);
mainEditText.setSelection(mainEditText.length());
if(!TextUtils.isEmpty(replyTo.spoilerText) && AccountSessionManager.getInstance().isSelf(accountID, replyTo.account)){
// TODO: setting for preserving cw always / only when replying to own posts
// && AccountSessionManager.getInstance().isSelf(accountID, replyTo.account)
if(!TextUtils.isEmpty(replyTo.spoilerText)){
hasSpoiler=true;
spoilerEdit.setVisibility(View.VISIBLE);
spoilerEdit.setText(replyTo.spoilerText);

View File

@@ -255,9 +255,14 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
@Override
public boolean onBackPressed(){
if(currentTab==R.id.tab_profile)
return profileFragment.onBackPressed();
if (profileFragment.onBackPressed()) return true;
if(currentTab==R.id.tab_search)
return searchFragment.onBackPressed();
if (searchFragment.onBackPressed()) return true;
if (currentTab!=R.id.tab_home) {
tabBar.selectTab(R.id.tab_home);
onTabSelected(R.id.tab_home);
return true;
}
return false;
}

View File

@@ -522,7 +522,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if(isOwnProfile){
for(int i=0;i<menu.size();i++){
MenuItem item=menu.getItem(i);
item.setVisible(item.getItemId()==R.id.share);
item.setVisible(item.getItemId()==R.id.share || item.getItemId()==R.id.bookmarks);
}
return;
}
@@ -542,11 +542,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@Override
public boolean onOptionsItemSelected(MenuItem item){
int id=item.getItemId();
if(id==R.id.share){
Intent intent=new Intent(Intent.ACTION_SEND);
if(id==R.id.share) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, account.url);
startActivity(Intent.createChooser(intent, item.getTitle()));
}else if(id==R.id.bookmarks) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("profileAccount", Parcels.wrap(account));
Nav.go(getActivity(), BookmarksListFragment.class, args);
}else if(id==R.id.mute){
confirmToggleMuted();
}else if(id==R.id.block){

View File

@@ -43,7 +43,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
private final TextView reply, boost, favorite;
private final TextView reply, boost, favorite, bookmark;
private final ImageView share;
private final View.AccessibilityDelegate buttonAccessibilityDelegate=new View.AccessibilityDelegate(){
@@ -60,22 +60,27 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
reply=findViewById(R.id.reply);
boost=findViewById(R.id.boost);
favorite=findViewById(R.id.favorite);
bookmark=findViewById(R.id.bookmark);
share=findViewById(R.id.share);
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N){
UiUtils.fixCompoundDrawableTintOnAndroid6(reply);
UiUtils.fixCompoundDrawableTintOnAndroid6(boost);
UiUtils.fixCompoundDrawableTintOnAndroid6(favorite);
UiUtils.fixCompoundDrawableTintOnAndroid6(bookmark);
}
View reply=findViewById(R.id.reply_btn);
View boost=findViewById(R.id.boost_btn);
View favorite=findViewById(R.id.favorite_btn);
View share=findViewById(R.id.share_btn);
View bookmark=findViewById(R.id.bookmark_btn);
reply.setOnClickListener(this::onReplyClick);
reply.setAccessibilityDelegate(buttonAccessibilityDelegate);
boost.setOnClickListener(this::onBoostClick);
boost.setAccessibilityDelegate(buttonAccessibilityDelegate);
favorite.setOnClickListener(this::onFavoriteClick);
favorite.setAccessibilityDelegate(buttonAccessibilityDelegate);
bookmark.setOnClickListener(this::onBookmarkClick);
bookmark.setAccessibilityDelegate(buttonAccessibilityDelegate);
share.setOnClickListener(this::onShareClick);
share.setAccessibilityDelegate(buttonAccessibilityDelegate);
}
@@ -87,6 +92,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
bindButton(favorite, item.status.favouritesCount);
boost.setSelected(item.status.reblogged);
favorite.setSelected(item.status.favourited);
bookmark.setSelected(item.status.bookmarked);
boost.setEnabled(item.status.visibility==StatusPrivacy.PUBLIC || item.status.visibility==StatusPrivacy.UNLISTED
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
}
@@ -120,6 +126,11 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
bindButton(favorite, item.status.favouritesCount);
}
private void onBookmarkClick(View v){
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked);
bookmark.setSelected(item.status.bookmarked);
}
private void onShareClick(View v){
Intent intent=new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
@@ -134,6 +145,8 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
return R.string.button_reblog;
if(id==R.id.favorite_btn)
return R.string.button_favorite;
if(id==R.id.bookmark_btn)
return R.string.button_bookmark;
if(id==R.id.share_btn)
return R.string.button_share;
return 0;

View File

@@ -36,7 +36,7 @@ public class ImageAttachmentFrameLayout extends FrameLayout{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int w=Math.min(((View)getParent()).getMeasuredWidth()-horizontalInset, V.dp(MAX_WIDTH));
int w=Math.min(((View)getParent()).getMeasuredWidth(), V.dp(MAX_WIDTH))-horizontalInset;
int actualHeight=Math.round(tile.height/1000f*w)+V.dp(1)*(tile.rowSpan-1);
int actualWidth=Math.round(tile.width/1000f*w);
if(tile.startCol+tile.colSpan<tileLayout.columnSizes.length)

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/bookmark_selected" android:state_selected="true"/>
<item android:color="?android:textColorSecondary"/>
</selector>

View File

@@ -0,0 +1,7 @@
<vector android:height="108dp"
android:viewportHeight="48" android:viewportWidth="48"
android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group android:translateX="12" android:translateY="12">
<path android:fillColor="@color/shortcut_icon_foreground" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</group>
</vector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M6.19 21.855c-0.495 0.357-1.187 0.002-1.187-0.61V6.25C5.003 4.455 6.458 3 8.253 3h7.498c1.795 0 3.25 1.455 3.25 3.25v14.996c0 0.611-0.692 0.966-1.188 0.609l-5.81-4.181-5.812 4.18z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M6.19 21.855c-0.495 0.357-1.187 0.002-1.187-0.61V6.25C5.003 4.455 6.458 3 8.253 3h7.498c1.795 0 3.25 1.455 3.25 3.25v14.996c0 0.611-0.692 0.966-1.188 0.609l-5.81-4.181-5.812 4.18zM17.502 6.25c0-0.966-0.783-1.75-1.75-1.75H8.253c-0.967 0-1.75 0.784-1.75 1.75v13.532l5.061-3.641c0.262-0.188 0.614-0.188 0.876 0l5.061 3.641V6.25z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--~ Copyright (c) 2022. ~ Microsoft Corporation. All rights reserved.-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_fluent_bookmark_24_filled" android:state_activated="true"/>
<item android:drawable="@drawable/ic_fluent_bookmark_24_filled" android:state_checked="true"/>
<item android:drawable="@drawable/ic_fluent_bookmark_24_filled" android:state_selected="true"/>
<item android:drawable="@drawable/ic_fluent_bookmark_24_regular"/>
</selector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M4 6.748c0-1.243 1.007-2.25 2.25-2.25h9c1.243 0 2.25 1.007 2.25 2.25V21.25c0 0.268-0.143 0.517-0.376 0.65-0.233 0.134-0.52 0.133-0.751-0.002l-5.623-3.28-5.622 3.28c-0.232 0.135-0.519 0.136-0.752 0.002C4.144 21.767 4 21.52 4 21.25V6.748zM15.25 2C17.873 2 20 4.127 20 6.75v11.873c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75V6.751c0-1.796-1.455-3.25-3.25-3.25H6.637S6.75 2.942 7.434 2.42C8 2 8.602 2 8.602 2h6.648z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -73,6 +73,28 @@
tools:text="123"/>
</FrameLayout>
<Space
android:layout_width="0px"
android:layout_height="1px"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/bookmark_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="56dp">
<TextView
android:id="@+id/bookmark"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center"
android:drawableStart="@drawable/ic_fluent_bookmark_24_selector"
android:drawablePadding="8dp"
android:drawableTint="@color/bookmark_icon"
android:gravity="center_vertical"
android:textAppearance="@style/m3_label_large" />
</FrameLayout>
<Space
android:layout_width="0px"
android:layout_height="1px"

View File

@@ -9,20 +9,21 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<org.joinmastodon.android.ui.views.ComposeMediaLayout
android:layout_width="wrap_content"
<org.joinmastodon.android.ui.views.MaxWidthFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
android:layout_gravity="center"
android:maxWidth="400dp">
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:importantForAccessibility="no"
tools:src="#0f0"/>
</org.joinmastodon.android.ui.views.ComposeMediaLayout>
</org.joinmastodon.android.ui.views.MaxWidthFrameLayout>
<TextView
android:id="@+id/title"

View File

@@ -7,4 +7,10 @@
<item android:id="@+id/block_domain" android:title="@string/block_domain"/>
<item android:id="@+id/hide_boosts" android:title="@string/hide_boosts_from_user"/>
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser"/>
<item
android:id="@+id/bookmarks"
android:showAsAction="always"
android:visible="false"
android:icon="@drawable/ic_fluent_bookmark_multiple_24_filled"
android:title="@string/bookmarks"/>
</menu>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background>
<shape>
<solid android:color="@color/shortcut_icon_background"/>
<size android:width="108dp" android:height="108dp"/>
</shape>
</background>
<foreground android:drawable="@drawable/ic_compose_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="shortcut_icon_background">@color/gray_700</color>
<color name="shortcut_icon_foreground">@color/primary_600</color>
</resources>

View File

@@ -92,5 +92,9 @@
<color name="highlight_over_light">#18000000</color>
<color name="favorite_selected">@color/warning_500</color>
<color name="bookmark_selected">@color/success_500</color>
<color name="boost_selected">@color/primary_500</color>
<color name="shortcut_icon_background">@color/gray_100</color>
<color name="shortcut_icon_foreground">@color/primary_700</color>
</resources>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Maston</string>
<string name="app_name" translatable="false">Mastadon</string>
<string name="get_started">Get started</string>
<string name="log_in">Log in</string>
@@ -289,6 +289,8 @@
<string name="button_reblog">Reblog</string>
<string name="button_favorite">Favorite</string>
<string name="button_share">Share</string>
<string name="button_bookmark">Bookmark</string>
<string name="bookmarks">Bookmarks</string>
<string name="media_no_description">Media without description</string>
<string name="add_media">Add media</string>
<string name="add_poll">Add a poll</string>