Compare commits

...

80 Commits

Author SHA1 Message Date
LucasGGamerM
e15dd6024f Bumped version number 2022-12-07 13:28:07 -03:00
LucasGGamerM
e52dffeece Fix notification logo and lets start splash screen button color 2022-12-07 12:46:26 -03:00
LucasGGamerM
5b85bb427d bumping version code 2022-12-07 09:50:03 -03:00
LucasGGamerM
4d62388617 Fixing the notification icon once again... 2022-12-07 09:36:50 -03:00
LucasGGamerM
04b8055474 Fixing the notification icon once more 2022-12-07 09:22:18 -03:00
LucasGGamerM
3c34b6a7d2 Upping the version code once more, and fixing the self updater 2022-12-06 22:06:49 -03:00
LucasGGamerM
de4964c2cd Upping the version code and changing notification icon. This should be the first release 2022-12-06 21:58:35 -03:00
LucasGGamerM
fbcaa05c03 Changing the name of the archivesBaseName 2022-12-06 21:49:46 -03:00
LucasGGamerM
883f28696e Editing a while lot of files. New icon, new notification icon, a bunch of new stuff! 2022-12-06 21:21:43 -03:00
LucasGGamerM
df52230837 Editing the readme just in case 2022-12-06 19:23:28 -03:00
LucasGGamerM
a90f26a37a Setting update client 2022-12-06 19:20:47 -03:00
LucasGGamerM
8c1f76d7fa Initial Moshidon "release" 2022-12-06 19:17:07 -03:00
LucasGGamerM
f384d44f8f Changing my app id 2022-12-06 13:03:26 -03:00
LucasGGamerM
4ab6ed55f5 Changing my version number and string 2022-12-06 12:41:03 -03:00
LucasGGamerM
cf99bf5152 Merge branch 'proper_implementation_of_the_color_picker'
Just fixing stuff here and there
2022-12-05 17:47:03 -03:00
LucasGGamerM
10779717cf Make follow requests icon badge follow the color scheme and also make it that the profile top bar menu also follows the theme. This should be it 2022-12-05 17:20:40 -03:00
LucasGGamerM
db4c1bfe47 Merge branch 'proper_implementation_of_the_color_picker'
Just making it tidy and better :D
2022-12-05 14:11:20 -03:00
LucasGGamerM
27afba1cf2 Making it so that the boost icon is also following the theme when clicked 2022-12-05 14:10:34 -03:00
LucasGGamerM
4895425b40 Adding a proper logo to the top of the home timeline 2022-12-05 13:27:09 -03:00
LucasGGamerM
004c414fba Editing some drawable files to make them also follow the theme 2022-12-05 09:41:56 -03:00
LucasGGamerM
c8e38b134c Fixing weird bug with the buttons for the second time 2022-12-05 09:03:48 -03:00
LucasGGamerM
de5a911286 Fixing weird bug with the buttons 2022-12-04 22:52:27 -03:00
LucasGGamerM
606cd7442e Make it so that the publish button also follows the theme 2022-12-04 14:45:42 -03:00
LucasGGamerM
3ebc972268 Fixing the TrueBlack themes for everything 2022-12-04 14:00:10 -03:00
LucasGGamerM
4e39bb381c Making it so that the fab follows the theme 2022-12-04 13:14:38 -03:00
LucasGGamerM
b6178681b0 Adding yellow theme 2022-12-04 11:42:41 -03:00
LucasGGamerM
29abf70cec Adding orange theme, tweaking the blue and green theme 2022-12-04 11:16:58 -03:00
LucasGGamerM
8d63be513d Fix readability issue on the light blue theme 2022-12-04 10:24:51 -03:00
LucasGGamerM
e63b9d0dd6 Adding an icon to the color picker setting 2022-12-03 22:29:41 -03:00
LucasGGamerM
b1fda17ac7 Make badged settings icon follow accent colors 2022-12-03 16:48:12 -03:00
LucasGGamerM
bad44b145c Adding blue theme and refactoring styles.xml 2022-12-03 16:25:28 -03:00
LucasGGamerM
77669cedf6 More polishes over the green theme 2022-12-03 13:44:40 -03:00
LucasGGamerM
19238c389f Making the green theme more readable 2022-12-03 12:29:51 -03:00
LucasGGamerM
1747ff98b5 Adding a green theme 2022-12-02 14:00:58 -03:00
LucasGGamerM
8fa5824e3e Disabling the icons for the color picker menu 2022-12-02 11:58:40 -03:00
LucasGGamerM
6a674d7a7e Polishes 2022-12-01 19:55:53 -03:00
LucasGGamerM
dad3b8cd6b Proper implementation on the color picker. 2022-12-01 19:42:21 -03:00
LucasGGamerM
9179d2198d Fully fixed now, it should be ready to release. 2022-11-29 13:09:32 -03:00
LucasGGamerM
d096bef234 Fixing the fix of the bug I found. 2022-11-28 21:30:32 -03:00
LucasGGamerM
f2c47a1b84 Fixing another bug I found. 2022-11-28 21:24:00 -03:00
LucasGGamerM
bc2ac4e915 Fixed a few bugs from the earlier commit. 2022-11-28 16:47:04 -03:00
LucasGGamerM
ff215412c8 Adding mastodon original colors toggle. Partially fixing #90 2022-11-28 15:40:29 -03:00
sk
e6bb319d8b add changelog and update readme 2022-11-28 18:43:57 +01:00
sk
3101f1ad17 bump version 2022-11-28 18:30:49 +01:00
sk
4416dfcae3 Merge branch 'feature/clickable-reply-line-compose' into fork 2022-11-28 18:28:31 +01:00
sk
924b974b4b make reply line open post 2022-11-28 18:26:21 +01:00
sk
5d1dc97ac3 change contribute link 2022-11-28 17:54:02 +01:00
sk
5cce8ca72c add release without federated timeline 2022-11-28 17:50:26 +01:00
sk
f2a0680af0 Merge branch 'fork' of github.com:sk22/megalodon into fork 2022-11-28 12:07:38 +01:00
sk
6203ded864 Merge branch 'main' into fork 2022-11-28 12:07:35 +01:00
sk22
17f1eb88e4 Merge pull request #110 from Surendrajat/rip-appcenter
Get rid of Microsoft appcenter related stuff
2022-11-28 10:11:18 +01:00
sk
9a52cc033a set custom redirect uri
closes #89
2022-11-28 10:00:57 +01:00
Grishka
4b16262a1a Sync last seen notification ID with server 2022-11-27 13:39:50 +03:00
Grishka
10e7cbf022 Merge branch 'add/verified-profile-fields' 2022-11-27 13:15:13 +03:00
Grishka
531b8ead04 Make verified fields more like on iOS 2022-11-27 13:14:31 +03:00
Grishka
4b2c94ab52 Implement bookmarks and add favorites list
Closes #22, at last
2022-11-27 12:43:07 +03:00
Grishka
a98becf2f4 Update splash logo to purple 2022-11-27 11:40:55 +03:00
Grishka
54f9eace67 Fix #422 2022-11-27 10:02:47 +03:00
Grishka
e4c9eb089a Hide posts when muting, blocking or unfollowing an account 2022-11-26 23:09:46 +03:00
Grishka
0e635aec23 Allow copying the username in profile 2022-11-26 20:33:02 +03:00
Grishka
dc90c09cea Shorten interaction counters 2022-11-26 20:24:27 +03:00
Grishka
06cb335a0a Add tooltips to some icon buttons
closes #423
2022-11-26 20:21:48 +03:00
Grishka
5a681d3557 Fix #403 2022-11-26 20:16:43 +03:00
Grishka
4200486aeb fix 2022-11-26 20:14:30 +03:00
Grishka
62411a563f Fix poll expiration
fixes #238, fixes #417
2022-11-26 20:13:46 +03:00
Grishka
2cabe94ba0 Fix #398 2022-11-26 20:02:30 +03:00
Grishka
4a6baae97a Make URLs clickable in instance rules
closes #389
2022-11-26 19:29:05 +03:00
Grishka
bb12a66781 Fix #313 2022-11-26 18:40:17 +03:00
surendrajat
efa9f524f9 Get rid of Microsoft appcenter related stuff 2022-11-26 13:37:03 +05:30
sk
be0c7777b7 fix typo 2022-11-26 01:01:22 +01:00
sk
92652f6fbd update fastlane descriptions 2022-11-26 01:00:22 +01:00
sk
4ee781dfd5 update fastlane descriptions 2022-11-26 00:04:05 +01:00
sk
bf8ac4bc69 set archive name 2022-11-25 23:37:12 +01:00
sk
a8e7840c04 remove unused script 2022-11-25 23:30:36 +01:00
sk
c91ebda1ff set gradle project name 2022-11-25 23:23:52 +01:00
sk
e7dc5030d5 update fastlane config 2022-11-25 22:09:53 +01:00
sk
4cf55e23ba update readme 2022-11-25 22:08:19 +01:00
sk
8159af0b58 update fastlane config 2022-11-25 22:06:18 +01:00
Jeff Bowen
5d056d5bea AboutViewHolder: Set the background of the field item to green when verified 2022-11-16 19:01:32 -05:00
Jeff Bowen
f500cc7ebf IsoInstantTypeAdapter: Enable parsing of 'offset' date times in profile response 2022-11-16 19:00:11 -05:00
134 changed files with 1751 additions and 588 deletions

View File

@@ -1,10 +1,10 @@
![Pink logo with pink shark](mastodon/src/main/res/mipmap-xhdpi/ic_launcher_round.png)
# Megalodon
# Moshidon
> A fork of the [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly wont ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly wont ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
**Warning! [The latest version's integrated updater is broken](https://github.com/sk22/megalodon/issues/106) I'll publish a fixed version ASAP! If you're not updating through Izzy's F-Droid repository (more sources to come, hopefully!), you'll have to download the upcoming release manually. Sorry about that!**
**Warning! [The last version's integrated updater was broken](https://github.com/sk22/megalodon/issues/106) I already published a fixed version! If you're not updating through Izzy's F-Droid repository (more sources to come, hopefully!), you'll have to download the current release manually. Sorry about that!**
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=d92aad&label=download%20apk&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2Fsk22%2Fmastodon-android-fork%2Freleases%2Flatest&style=for-the-badge)](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk)
@@ -23,7 +23,7 @@ The Mastodon documentation has some more information about [Unlisted posting](ht
### **Federated timeline**
**This allows you to chronologically see all Public posts from people on all other Fediverse instances your home instance is connected to.**
**This allows you to chronologically see all Public posts from people on all other Fediverse neighborhoods your home instance is connected to.**
Despite being one of the main features of federated social media, the Federated timeline wasnt included in the official Mastodon app supposedly, because this conflicts with Googles safety requirements for apps on the Play Store.
@@ -66,8 +66,6 @@ Megalodon makes use of [Mastodon for Android](https://github.com/mastodon/mastod
All downloads can be found on the [Releases](https://github.com/sk22/megalodon/releases) page.
**Warning! [The latest version's integrated updater is broken](https://github.com/sk22/megalodon/issues/106) I'll publish a fixed version ASAP! If you're not updating through Izzy's F-Droid repository (more sources to come, hopefully!), you'll have to download the upcoming release manually. Sorry about that!**
**`megalodon.apk`**
Variant with an integrated updater. If you download Megalodon from here (and not from an app store), just download the regular `megalodon.apk`.
@@ -106,7 +104,7 @@ Variant without the integrated updater. This is the variant to be published to F
* [Add notifications tab for posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/posts-notifications-tab)
* [Show visibility of original post when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-reply-visibility)
* [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line)
* [Long-click to copy username from profile](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/copy-username)
* [Clickable reply line while replying to open original post](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/clickable-reply-line-compose)
### Behavior

View File

@@ -6,7 +6,6 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@@ -1,3 +0,0 @@
#!/bin/sh
git rev-parse --short --verify upstream/master

View File

@@ -1,16 +1,16 @@
plugins {
id 'com.android.application'
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}
android {
compileSdk 33
defaultConfig {
applicationId "org.joinmastodon.android.sk"
archivesBaseName = "moshidon"
applicationId "org.joinmastodon.android.moshinda"
minSdk 23
targetSdk 33
versionCode 50
versionName "1.1.4+fork.50"
versionCode 56
versionName "1.1.4+fork.56.moshinda"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "en", "ar-rSA", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES",
"eu-rES", "fi-rFI", "fr-rFR", "gl-rES", "hr-rHR", "hy-rAM", "it-rIT", "iw-rIL",
@@ -29,19 +29,13 @@ android {
versionNameSuffix '-debug'
applicationIdSuffix '.debug'
}
appcenterPrivateBeta{
initWith release
minifyEnabled false
shrinkResources false
versionNameSuffix "-priv-beta"
}
appcenterPublicBeta{
initWith release
versionNameSuffix "-beta"
}
githubRelease{
initWith release
}
noFederatedRelease{
initWith release
versionNameSuffix '-nofederated'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
@@ -49,12 +43,6 @@ android {
coreLibraryDesugaringEnabled true
}
sourceSets{
appcenterPrivateBeta{
setRoot "src/appcenter"
}
appcenterPublicBeta{
setRoot "src/appcenter"
}
githubRelease{
setRoot "src/github"
}
@@ -86,12 +74,6 @@ dependencies {
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
def appCenterSdkVersion = "4.4.2"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
androidTestImplementation 'androidx.test:core:1.4.1-alpha05'
androidTestImplementation 'androidx.test.ext:junit:1.1.4-alpha05'
androidTestImplementation 'androidx.test:runner:1.5.0-alpha02'

View File

@@ -40,12 +40,6 @@
@com.squareup.otto.Subscribe <methods>;
}
-keep class com.microsoft.appcenter.** {
*;
}
-keep class org.joinmastodon.android.AppCenterWrapper { *; }
-keepattributes LineNumberTable
# Parceler library

View File

@@ -1,23 +0,0 @@
package org.joinmastodon.android;
import android.app.Application;
import android.util.Log;
import com.microsoft.appcenter.AppCenter;
import com.microsoft.appcenter.crashes.Crashes;
import com.microsoft.appcenter.distribute.Distribute;
import com.microsoft.appcenter.distribute.UpdateTrack;
public class AppCenterWrapper{
private static final String TAG="AppCenterWrapper";
public static void init(Application app){
if(AppCenter.isConfigured())
return;
Log.i(TAG, "initializing AppCenter SDK, build type is "+BuildConfig.BUILD_TYPE);
if(BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta"))
Distribute.setUpdateTrack(UpdateTrack.PRIVATE);
AppCenter.start(app, BuildConfig.appCenterKey, Distribute.class, Crashes.class);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -111,7 +111,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
private void actuallyCheckForUpdates(){
Request req=new Request.Builder()
.url("https://api.github.com/repos/sk22/megalodon/releases/latest")
.url("https://api.github.com/repos/LucasGGamerM/moshidon/releases/latest")
.build();
Call call=MastodonAPIController.getHttpClient().newCall(req);
try(Response resp=call.execute()){
@@ -144,7 +144,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
Log.d(TAG, "actuallyCheckForUpdates: new version: "+version);
for(JsonElement el:obj.getAsJsonArray("assets")){
JsonObject asset=el.getAsJsonObject();
if("megalodon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
if("moshidon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
long size=asset.get("size").getAsLong();
String url=asset.get("browser_download_url").getAsString();

View File

@@ -8,7 +8,6 @@
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
@@ -20,7 +19,7 @@
android:localeConfig="@xml/locales_config"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.Mastodon.AutoLightDark"
android:theme="@style/Theme.Mastodon.AutoLightDark.Original"
android:largeHeap="true">
<activity android:name=".MainActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize" android:launchMode="singleTask">
@@ -34,7 +33,7 @@
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="mastodon-android-auth" android:host="callback"/>
<data android:scheme="megalodon-android-auth" android:host="callback"/>
</intent-filter>
</activity>
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -14,6 +14,7 @@ public class GlobalUserPreferences{
public static boolean alwaysExpandContentWarnings;
public static boolean disableMarquee;
public static ThemePreference theme;
public static ColorPreference color;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -31,6 +32,7 @@ public class GlobalUserPreferences{
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
disableMarquee=prefs.getBoolean("disableMarquee", false);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
color=ColorPreference.values()[prefs.getInt("color", 1)];
}
public static void save(){
@@ -45,12 +47,23 @@ public class GlobalUserPreferences{
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
.putBoolean("disableMarquee", disableMarquee)
.putInt("theme", theme.ordinal())
.putInt("color", color.ordinal())
.apply();
}
public enum ColorPreference{
PINK,
PURPLE,
GREEN,
BLUE,
ORANGE,
YELLOW
}
public enum ThemePreference{
AUTO,
LIGHT,
DARK
}
}

View File

@@ -1,10 +1,8 @@
package org.joinmastodon.android;
import android.Manifest;
import android.app.Application;
import android.app.Fragment;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
@@ -24,8 +22,6 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import org.parceler.Parcels;
import java.lang.reflect.InvocationTargetException;
import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
@@ -70,12 +66,7 @@ public class MainActivity extends FragmentStackActivity{
}
}
if(BuildConfig.BUILD_TYPE.startsWith("appcenter")){
// Call the appcenter SDK wrapper through reflection because it is only present in beta builds
try{
Class.forName("org.joinmastodon.android.AppCenterWrapper").getMethod("init", Application.class).invoke(null, getApplication());
}catch(ClassNotFoundException|NoSuchMethodException|IllegalAccessException|InvocationTargetException ignore){}
}else if(GithubSelfUpdater.needSelfUpdating()){
if(GithubSelfUpdater.needSelfUpdating()){
GithubSelfUpdater.getInstance().maybeCheckForUpdates();
}
}

View File

@@ -6,8 +6,6 @@ import android.content.Context;
import org.joinmastodon.android.api.PushSubscriptionManager;
import java.lang.reflect.InvocationTargetException;
import me.grishka.appkit.imageloader.ImageCache;
import me.grishka.appkit.utils.NetworkUtils;
import me.grishka.appkit.utils.V;

View File

@@ -1,5 +1,6 @@
package org.joinmastodon.android.api;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import java.io.IOException;
@@ -26,6 +27,9 @@ public class JsonObjectRequestBody extends RequestBody{
public void writeTo(BufferedSink sink) throws IOException{
try{
OutputStreamWriter writer=new OutputStreamWriter(sink.outputStream(), StandardCharsets.UTF_8);
if(obj instanceof JsonElement)
writer.write(obj.toString());
else
MastodonAPIController.gson.toJson(obj, writer);
writer.flush();
}catch(JsonIOException x){

View File

@@ -365,6 +365,8 @@ public class PushSubscriptionManager{
}
private static void registerAllAccountsForPush(boolean forceReRegister){
if(!arePushNotificationsAvailable())
return;
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
if(session.pushSubscription==null || forceReRegister)
session.getPushSubscriptionManager().registerAccountForPush(session.pushSubscription);

View File

@@ -63,36 +63,6 @@ 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");
@@ -130,4 +100,34 @@ public class StatusInteractionController{
status.reblogsCount--;
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));
}
}

View File

@@ -25,10 +25,21 @@ public class IsoInstantTypeAdapter extends TypeAdapter<Instant>{
in.nextNull();
return null;
}
try{
return DateTimeFormatter.ISO_INSTANT.parse(in.nextString(), Instant::from);
}catch(DateTimeParseException x){
String nextString;
try {
nextString = in.nextString();
}catch(Exception e){
return null;
}
try{
return DateTimeFormatter.ISO_INSTANT.parse(nextString, Instant::from);
}catch(DateTimeParseException x){}
try{
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(nextString, Instant::from);
}catch(DateTimeParseException x){}
return null;
}
}

View File

@@ -0,0 +1,42 @@
package org.joinmastodon.android.api.gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
public class JsonArrayBuilder{
private JsonArray arr=new JsonArray();
public JsonArrayBuilder add(JsonElement el){
arr.add(el);
return this;
}
public JsonArrayBuilder add(String el){
arr.add(el);
return this;
}
public JsonArrayBuilder add(Number el){
arr.add(el);
return this;
}
public JsonArrayBuilder add(boolean el){
arr.add(el);
return this;
}
public JsonArrayBuilder add(JsonObjectBuilder el){
arr.add(el.build());
return this;
}
public JsonArrayBuilder add(JsonArrayBuilder el){
arr.add(el.build());
return this;
}
public JsonArray build(){
return arr;
}
}

View File

@@ -0,0 +1,42 @@
package org.joinmastodon.android.api.gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class JsonObjectBuilder{
private JsonObject obj=new JsonObject();
public JsonObjectBuilder add(String key, JsonElement el){
obj.add(key, el);
return this;
}
public JsonObjectBuilder add(String key, String el){
obj.addProperty(key, el);
return this;
}
public JsonObjectBuilder add(String key, Number el){
obj.addProperty(key, el);
return this;
}
public JsonObjectBuilder add(String key, boolean el){
obj.addProperty(key, el);
return this;
}
public JsonObjectBuilder add(String key, JsonObjectBuilder el){
obj.add(key, el.build());
return this;
}
public JsonObjectBuilder add(String key, JsonArrayBuilder el){
obj.add(key, el.build());
return this;
}
public JsonObject build(){
return obj;
}
}

View File

@@ -1,52 +0,0 @@
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

@@ -1,49 +0,0 @@
package org.joinmastodon.android.api.requests.accounts;
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.List;
import okhttp3.Response;
public class GetFavourites extends MastodonAPIRequest<List<Status>>{
private String maxId;
public GetFavourites(String maxID, String minID, int limit){
super(HttpMethod.GET, "/favourites", 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

@@ -2,49 +2,15 @@ package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FollowSuggestion;
import java.io.IOException;
import java.util.List;
import okhttp3.Response;
public class GetFollowRequests extends MastodonAPIRequest<List<Account>>{
private String maxId;
public GetFollowRequests(String maxID, String minID, int limit){
public class GetFollowRequests extends HeaderPaginationRequest<Account>{
public GetFollowRequests(String maxID, int limit){
super(HttpMethod.GET, "/follow_requests", 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<Account> respObj, Response httpResponse) throws IOException {
super.validateAndPostprocessResponse(respObj, httpResponse);
// <https://mastodon.social/api/v1/follow_requests?max_id=268962>; rel="next",
// <https://mastodon.social/api/v1/follow_requests?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,21 @@
package org.joinmastodon.android.api.requests.markers;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.gson.JsonObjectBuilder;
import org.joinmastodon.android.model.Marker;
public class SaveMarkers extends MastodonAPIRequest<SaveMarkers.Response>{
public SaveMarkers(String lastSeenHomePostID, String lastSeenNotificationID){
super(HttpMethod.POST, "/markers", Response.class);
JsonObjectBuilder builder=new JsonObjectBuilder();
if(lastSeenHomePostID!=null)
builder.add("home", new JsonObjectBuilder().add("last_read_id", lastSeenHomePostID));
if(lastSeenNotificationID!=null)
builder.add("notifications", new JsonObjectBuilder().add("last_read_id", lastSeenNotificationID));
setRequestBody(builder.build());
}
public static class Response{
public Marker home, notifications;
}
}

View File

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.statuses;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.Status;
public class GetBookmarkedStatuses extends HeaderPaginationRequest<Status>{
public GetBookmarkedStatuses(String maxID, int limit){
super(HttpMethod.GET, "/bookmarks", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
}
}

View File

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.statuses;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.Status;
public class GetFavoritedStatuses extends HeaderPaginationRequest<Status>{
public GetFavoritedStatuses(String maxID, int limit){
super(HttpMethod.GET, "/favourites", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
}
}

View File

@@ -61,7 +61,7 @@ import me.grishka.appkit.api.ErrorResponse;
public class AccountSessionManager{
private static final String TAG="AccountSessionManager";
public static final String SCOPE="read write follow push";
public static final String REDIRECT_URI="mastodon-android-auth://callback";
public static final String REDIRECT_URI="megalodon-android-auth://callback";
private static final AccountSessionManager instance=new AccountSessionManager();
@@ -211,7 +211,7 @@ public class AccountSessionManager{
.path("/oauth/authorize")
.appendQueryParameter("response_type", "code")
.appendQueryParameter("client_id", result.clientId)
.appendQueryParameter("redirect_uri", "mastodon-android-auth://callback")
.appendQueryParameter("redirect_uri", "megalodon-android-auth://callback")
.appendQueryParameter("scope", SCOPE)
.build();

View File

@@ -0,0 +1,13 @@
package org.joinmastodon.android.events;
public class RemoveAccountPostsEvent{
public final String accountID;
public final String postsByAccountID;
public final boolean isUnfollow;
public RemoveAccountPostsEvent(String accountID, String postsByAccountID, boolean isUnfollow){
this.accountID=accountID;
this.postsByAccountID=postsByAccountID;
this.isUnfollow=isUnfollow;
}
}

View File

@@ -5,7 +5,7 @@ import org.joinmastodon.android.model.Status;
public class StatusCountersUpdatedEvent{
public String id;
public long favorites, reblogs, replies;
public boolean favorited, reblogged, pinned;
public boolean favorited, reblogged, bookmarked, pinned;
public StatusCountersUpdatedEvent(Status s){
id=s.id;
@@ -14,6 +14,7 @@ public class StatusCountersUpdatedEvent{
replies=s.repliesCount;
favorited=s.favourited;
reblogged=s.reblogged;
bookmarked=s.bookmarked;
pinned=s.pinned;
}
}

View File

@@ -3,9 +3,11 @@ package org.joinmastodon.android.events;
import org.joinmastodon.android.model.Status;
public class StatusCreatedEvent{
public Status status;
public final Status status;
public final String accountID;
public StatusCreatedEvent(Status status){
public StatusCreatedEvent(Status status, String accountID){
this.status=status;
this.accountID=accountID;
}
}

View File

@@ -7,6 +7,7 @@ import android.view.View;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusUnpinnedEvent;
import org.joinmastodon.android.model.Account;
@@ -109,4 +110,9 @@ public class AccountTimelineFragment extends StatusListFragment{
displayItems.subList(index, lastIndex).clear();
adapter.notifyItemRangeRemoved(index, lastIndex-index);
}
@Override
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
}

View File

@@ -444,7 +444,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
error.showToast(getActivity());
}
})
.wrapProgress(getActivity(), R.string.loading, false)
.wrapProgress(getActivity(), R.string.loading, true)
.exec(accountID);
}

View File

@@ -0,0 +1,37 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
import me.grishka.appkit.api.SimpleCallback;
public class BookmarkedStatusListFragment extends StatusListFragment{
private String nextMaxID;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
setTitle(R.string.bookmarks);
loadData();
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetBookmarkedStatuses(offset==0 ? null : nextMaxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
nextMaxID=null;
onDataLoaded(result, nextMaxID!=null);
}
})
.exec(accountID);
}
}

View File

@@ -1,53 +0,0 @@
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

@@ -28,7 +28,6 @@ import android.text.Layout;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -52,7 +51,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.twitter.twittertext.Regex;
import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E;
@@ -102,7 +100,6 @@ import org.parceler.Parcels;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
@@ -133,21 +130,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))");
private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))");
private static final String VALID_URL_PATTERN_STRING =
"(" + // $1 total match
"(" + Regex.URL_VALID_PRECEDING_CHARS + ")" + // $2 Preceding character
"(" + // $3 URL
"(https?://)" + // $4 Protocol (optional)
"(" + Regex.URL_VALID_DOMAIN + ")" + // $5 Domain(s)
"(?::(" + Regex.URL_VALID_PORT_NUMBER + "))?" + // $6 Port number (optional)
"(/" +
Regex.URL_VALID_PATH + "*+" +
")?" + // $7 URL Path and anchor
"(\\?" + Regex.URL_VALID_URL_QUERY_CHARS + "*" + // $8 Query String
Regex.URL_VALID_URL_QUERY_ENDING_CHARS + ")?" +
")" +
")";
private static final Pattern URL_PATTERN=Pattern.compile(VALID_URL_PATTERN_STRING, Pattern.CASE_INSENSITIVE);
@SuppressLint("NewApi") // this class actually exists on 6.0
private final BreakIterator breakIterator=BreakIterator.getCharacterInstance();
@@ -521,6 +503,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
replyArrow.setBounds(0, 0, V.dp(20), V.dp(20));
replyText.setCompoundDrawables(replyArrow, null, visibilityIcon, null);
replyText.setOnClickListener(v->{
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("status", Parcels.wrap(replyTo));
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
Nav.go(getActivity(), ThreadFragment.class, args);
});
ArrayList<String> mentions=new ArrayList<>();
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
if(!replyTo.account.id.equals(ownID))
@@ -644,7 +633,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
String countableText=TwitterTextEmojiRegex.VALID_EMOJI_PATTERN.matcher(
MENTION_PATTERN.matcher(
URL_PATTERN.matcher(text).replaceAll("$2xxxxxxxxxxxxxxxxxxxxxxx")
HtmlParser.URL_PATTERN.matcher(text).replaceAll("$2xxxxxxxxxxxxxxxxxxxxxxx")
).replaceAll("$1@$3")
).replaceAll("x");
charCount=0;
@@ -738,7 +727,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
wm.removeView(sendingOverlay);
sendingOverlay=null;
if(editingStatus==null){
E.post(new StatusCreatedEvent(result));
E.post(new StatusCreatedEvent(result, accountID));
if(replyTo!=null){
replyTo.repliesCount++;
E.post(new StatusCountersUpdatedEvent(replyTo));

View File

@@ -0,0 +1,37 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
import me.grishka.appkit.api.SimpleCallback;
public class FavoritedStatusListFragment extends StatusListFragment{
private String nextMaxID;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
setTitle(R.string.your_favorites);
loadData();
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetFavoritedStatuses(offset==0 ? null : nextMaxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
nextMaxID=null;
onDataLoaded(result, nextMaxID!=null);
}
})
.exec(accountID);
}
}

View File

@@ -1,46 +0,0 @@
package org.joinmastodon.android.fragments;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetFavourites;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Status;
import java.util.List;
import me.grishka.appkit.api.SimpleCallback;
public class FavoritesListFragment extends StatusListFragment{
private String accountID;
private String lastMaxId=null;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
setTitle(R.string.favorited_posts);
}
@Override
protected void onShown(){
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}
@Override
protected void doLoadData(int offset, int count) {
GetFavourites b=new GetFavourites(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

@@ -17,6 +17,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.accounts.GetFollowRequests;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -50,7 +51,7 @@ public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowReque
private String accountID;
private Map<String, Relationship> relationships=Collections.emptyMap();
private GetAccountRelationships relationshipsRequest;
private String lastMaxId=null;
private String nextMaxID;
public FollowRequestsListFragment(){
super(20);
@@ -75,10 +76,14 @@ public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowReque
relationshipsRequest.cancel();
relationshipsRequest=null;
}
currentRequest=new GetFollowRequests(offset>0 ? lastMaxId : null, null, count)
currentRequest=new GetFollowRequests(offset==0 ? null : nextMaxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Account> result){
public void onSuccess(HeaderPaginationList<Account> result){
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
nextMaxID=null;
onDataLoaded(result.stream().map(AccountWrapper::new).collect(Collectors.toList()), false);
loadRelationships();
}

View File

@@ -5,6 +5,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
@@ -17,6 +18,7 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toolbar;
@@ -56,7 +58,7 @@ import me.grishka.appkit.utils.V;
public class HomeTimelineFragment extends StatusListFragment{
private ImageButton fab;
private TextView toolbarLogo;
private ImageView toolbarLogo;
private Button toolbarShowNewPostsBtn;
private boolean newPostsBtnShown;
private AnimatorSet currentNewPostsAnim;
@@ -315,9 +317,13 @@ public class HomeTimelineFragment extends StatusListFragment{
}
private void updateToolbarLogo(){
toolbarLogo =new TextView(getActivity());
toolbarLogo.setText(getString(R.string.app_name).toLowerCase(Locale.getDefault()));
toolbarLogo.setTextAppearance(R.style.app_title);
toolbarLogo=new ImageView(getActivity());
toolbarLogo.setScaleType(ImageView.ScaleType.CENTER);
toolbarLogo.setImageResource(R.drawable.logo);
toolbarLogo.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary)));
// toolbarLogo =new TextView(getActivity());
// toolbarLogo.setText(getString(R.string.app_name).toLowerCase(Locale.getDefault()));
// toolbarLogo.setTextAppearance(R.style.app_title);
toolbarShowNewPostsBtn=new Button(getActivity());
toolbarShowNewPostsBtn.setTextAppearance(R.style.m3_title_medium);
@@ -432,4 +438,9 @@ public class HomeTimelineFragment extends StatusListFragment{
public void onSelfUpdateStateChanged(SelfUpdateStateChangedEvent ev){
updateUpdateState(ev.state);
}
@Override
protected boolean shouldRemoveAccountPostsWhenUnfollowing(){
return true;
}
}

View File

@@ -18,6 +18,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetFollowRequests;
import org.joinmastodon.android.events.FollowRequestHandledEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.ui.SimpleViewHolder;
import org.joinmastodon.android.ui.tabs.TabLayout;
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
@@ -29,8 +30,6 @@ import androidx.viewpager2.widget.ViewPager2;
import com.squareup.otto.Subscribe;
import java.util.List;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -167,9 +166,9 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
}
public void refreshFollowRequestsBadge() {
new GetFollowRequests(null, null, 1).setCallback(new Callback<>() {
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
@Override
public void onSuccess(List<Account> accounts) {
public void onSuccess(HeaderPaginationList<Account> accounts) {
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
}

View File

@@ -8,9 +8,11 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.NotificationDeletedEvent;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.Status;
@@ -27,6 +29,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
@@ -122,6 +125,10 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
.collect(Collectors.toSet());
loadRelationships(needRelationships);
maxID=result.maxID;
if(offset==0 && !result.items.isEmpty()){
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
}
}
});
}
@@ -192,14 +199,23 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
}
@Subscribe
public void onNotificationDeleted(NotificationDeletedEvent ev) {
Notification notification = getNotificationByID(ev.id);
if(notification==null)
public void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
if(!ev.accountID.equals(accountID) || ev.isUnfollow)
return;
data.remove(notification);
List<Notification> toRemove=Stream.concat(data.stream(), preloadedData.stream())
.filter(n->n.account!=null && n.account.id.equals(ev.postsByAccountID))
.collect(Collectors.toList());
for(Notification n:toRemove){
removeNotification(n);
}
}
private void removeNotification(Notification n){
data.remove(n);
preloadedData.remove(n);
int index=-1;
for(int i=0;i<displayItems.size();i++){
if(ev.id.equals(displayItems.get(i).parentID)){
if(n.id.equals(displayItems.get(i).parentID)){
index=i;
break;
}
@@ -208,11 +224,10 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
return;
int lastIndex;
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
if(!displayItems.get(lastIndex).parentID.equals(ev.id))
if(!displayItems.get(lastIndex).parentID.equals(n.id))
break;
}
displayItems.subList(index, lastIndex).clear();
adapter.notifyItemRangeRemoved(index, lastIndex-index);
}
}

View File

@@ -183,7 +183,7 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
}
private abstract class BaseViewHolder extends BindableViewHolder<AccountField>{
private ShapeDrawable background=new ShapeDrawable();
protected ShapeDrawable background=new ShapeDrawable();
public BaseViewHolder(int layout){
super(getActivity(), layout, list);
@@ -220,6 +220,20 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
super.onBind(item);
title.setText(item.parsedName);
value.setText(item.parsedValue);
if(item.verifiedAt!=null){
background.getPaint().setColor(UiUtils.isDarkTheme() ? 0xFF49595a : 0xFFd7e3da);
int textColor=UiUtils.isDarkTheme() ? 0xFF89bb9c : 0xFF5b8e63;
value.setTextColor(textColor);
value.setLinkTextColor(textColor);
Drawable check=getResources().getDrawable(R.drawable.ic_fluent_checkmark_24_regular, getActivity().getTheme()).mutate();
check.setTint(textColor);
value.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, check, null);
}else{
background.getPaint().setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
value.setTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary));
value.setLinkTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorAccent));
value.setCompoundDrawables(null, null, null, null);
}
}
@Override

View File

@@ -10,7 +10,6 @@ import android.app.Activity;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Outline;
@@ -19,8 +18,6 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
@@ -286,6 +283,18 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
followersBtn.setOnClickListener(this::onFollowersOrFollowingClick);
followingBtn.setOnClickListener(this::onFollowersOrFollowingClick);
username.setOnLongClickListener(v->{
String username=account.acct;
if(!username.contains("@")){
username+="@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
}
getActivity().getSystemService(ClipboardManager.class).setPrimaryClip(ClipData.newPlainText(null, "@"+username));
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.TIRAMISU){ // Android 13+ SystemUI shows its own thing when you put things into the clipboard
Toast.makeText(getActivity(), R.string.text_copied, Toast.LENGTH_SHORT).show();
}
return true;
});
return sizeWrapper;
}
@@ -453,16 +462,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
// noinspection SetTextI18n
username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
}
username.setOnLongClickListener(l->{
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE);
Vibrator v = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
ClipData clip = ClipData.newPlainText("Username", '@'+account.acct+'@'+AccountSessionManager.getInstance().getAccount(accountID).domain);
clipboard.setPrimaryClip(clip);
Toast.makeText(getActivity(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) v.vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE));
else v.vibrate(50);
return true;
});
CharSequence parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(TextUtils.isEmpty(parsedBio)){
bio.setVisibility(View.GONE);
@@ -548,17 +547,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
}
if(relationship==null && !isOwnProfile)
return;
inflater.inflate(R.menu.profile, menu);
inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu);
menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getDisplayUsername()));
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.lists_with_user, account.getDisplayUsername()));
if(isOwnProfile){
for(int i=0;i<menu.size();i++){
MenuItem item=menu.getItem(i);
item.setVisible(item.getItemId()==R.id.share || item.getItemId()==R.id.bookmarks || item.getItemId()==R.id.manage_user_lists);
}
menu.findItem(R.id.favorites_list).setVisible(true);
if(isOwnProfile)
return;
}
menu.findItem(R.id.mute).setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername()));
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername()));
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getDisplayUsername()));
@@ -582,16 +575,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
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.favorites_list) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("profileAccount", Parcels.wrap(account));
Nav.go(getActivity(), FavoritesListFragment.class, args);
}else if(id==R.id.mute){
confirmToggleMuted();
}else if(id==R.id.block){
@@ -623,6 +606,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
})
.wrapProgress(getActivity(), R.string.loading, false)
.exec(accountID);
}else if(id==R.id.bookmarks){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), BookmarkedStatusListFragment.class, args);
}else if(id==R.id.favorites){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), FavoritedStatusListFragment.class, args);
}else if(id==R.id.manage_user_lists){
final Bundle args=new Bundle();
args.putString("account", accountID);

View File

@@ -9,6 +9,7 @@ import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +37,7 @@ import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.PushSubscriptionManager;
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -98,6 +100,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.disableMarquee=i.checked;
GlobalUserPreferences.save();
}));
items.add(new ColorPicker());
items.add(new HeaderItem(R.string.settings_behavior));
items.add(new SwitchItem(R.string.settings_gif, R.drawable.ic_fluent_gif_24_regular, GlobalUserPreferences.playGifs, i->{
@@ -149,7 +152,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
checkForUpdateItem = new TextItem(R.string.check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
items.add(checkForUpdateItem);
}
items.add(new TextItem(R.string.settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/mastodon/mastodon-android")));
items.add(new TextItem(R.string.settings_contribute_fork, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon")));
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
items.add(new TextItem(R.string.log_out, this::confirmLogOut));
@@ -198,7 +201,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
@Override
public void onDestroy(){
super.onDestroy();
if(needUpdateNotificationSettings){
if(needUpdateNotificationSettings && PushSubscriptionManager.arePushNotificationsAvailable()){
AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().updatePushSettings(pushSubscription);
}
}
@@ -223,6 +226,12 @@ public class SettingsFragment extends MastodonToolbarFragment{
restartActivityToApplyNewTheme();
}
private void onColorPreferenceClick(GlobalUserPreferences.ColorPreference color){
GlobalUserPreferences.color=color;
GlobalUserPreferences.save();
restartActivityToApplyNewTheme();
}
private void onTrueBlackThemeChanged(SwitchItem item){
GlobalUserPreferences.trueBlackTheme=item.checked;
GlobalUserPreferences.save();
@@ -425,6 +434,13 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
}
public class ColorPicker extends Item{
@Override
public int getViewType(){
return 8;
}
}
private static class ThemeItem extends Item{
@Override
@@ -509,6 +525,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
case 5 -> new HeaderViewHolder(true);
case 6 -> new FooterViewHolder();
case 7 -> new UpdateViewHolder();
case 8 -> new ColorPickerViewHolder();
default -> throw new IllegalStateException("Unexpected value: "+viewType);
};
}
@@ -637,6 +654,68 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
}
}
private class ColorPickerViewHolder extends BindableViewHolder<ColorPicker>{
private final Button button;
private final PopupMenu popupMenu;
private final ImageView icon;
@SuppressLint("ClickableViewAccessibility")
public ColorPickerViewHolder(){
super(getActivity(), R.layout.item_settings_color_picker, list);
icon=findViewById(R.id.icon);
button=findViewById(R.id.color_picker_button);
popupMenu=new PopupMenu(getActivity(), button, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.color_picker);
popupMenu.setOnMenuItemClickListener(item->{
GlobalUserPreferences.ColorPreference pref;
int id=item.getItemId();
if(id==R.id.pink_color) {
pref = GlobalUserPreferences.ColorPreference.PINK;
onColorPreferenceClick(pref);
}
else if(id==R.id.purple_color) {
pref = GlobalUserPreferences.ColorPreference.PURPLE;
onColorPreferenceClick(pref);
}
else if(id==R.id.green_color) {
pref = GlobalUserPreferences.ColorPreference.GREEN;
onColorPreferenceClick(pref);
}
else if(id==R.id.blue_color) {
pref = GlobalUserPreferences.ColorPreference.BLUE;
onColorPreferenceClick(pref);
}
else if(id==R.id.orange_color) {
pref = GlobalUserPreferences.ColorPreference.ORANGE;
onColorPreferenceClick(pref);
}
else if(id==R.id.yellow_color) {
pref = GlobalUserPreferences.ColorPreference.YELLOW;
onColorPreferenceClick(pref);
}
else
return false;
return true;
});
// UiUtils.enablePopupMenuIcons(getActivity(), popupMenu);
button.setOnTouchListener(popupMenu.getDragToOpenListener());
button.setOnClickListener(v->popupMenu.show());
}
@Override
public void onBind(ColorPicker item){
icon.setImageResource(R.drawable.ic_color_theme_preference);
button.setText(switch(GlobalUserPreferences.color){
case PINK -> R.string.pink_color;
case PURPLE -> R.string.purple_color;
case GREEN -> R.string.green_color;
case BLUE -> R.string.blue_color;
case ORANGE -> R.string.orange_color;
case YELLOW -> R.string.yellow_color;
});
}
}
private class NotificationPolicyViewHolder extends BindableViewHolder<NotificationPolicyItem>{
private final Button button;

View File

@@ -6,6 +6,7 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusDeletedEvent;
@@ -18,6 +19,8 @@ import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
@@ -134,6 +137,40 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
return null;
}
protected boolean shouldRemoveAccountPostsWhenUnfollowing(){
return false;
}
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream())
.filter(s->s.account.id.equals(ev.postsByAccountID) || (s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
.collect(Collectors.toList());
for(Status s:toRemove){
removeStatus(s);
}
}
protected void removeStatus(Status status){
data.remove(status);
preloadedData.remove(status);
int index=-1;
for(int i=0;i<displayItems.size();i++){
if(status.id.equals(displayItems.get(i).parentID)){
index=i;
break;
}
}
if(index==-1)
return;
int lastIndex;
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
if(!displayItems.get(lastIndex).parentID.equals(status.id))
break;
}
displayItems.subList(index, lastIndex).clear();
adapter.notifyItemRangeRemoved(index, lastIndex-index);
}
public class EventListener{
@Subscribe
@@ -165,28 +202,13 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
Status status=getStatusByID(ev.id);
if(status==null)
return;
data.remove(status);
preloadedData.remove(status);
int index=-1;
for(int i=0;i<displayItems.size();i++){
if(ev.id.equals(displayItems.get(i).parentID)){
index=i;
break;
}
}
if(index==-1)
return;
int lastIndex;
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
if(!displayItems.get(lastIndex).parentID.equals(ev.id))
break;
}
displayItems.subList(index, lastIndex).clear();
adapter.notifyItemRangeRemoved(index, lastIndex-index);
removeStatus(status);
}
@Subscribe
public void onStatusCreated(StatusCreatedEvent ev){
if(!ev.accountID.equals(accountID))
return;
StatusListFragment.this.onStatusCreated(ev);
}
@@ -206,5 +228,14 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
}
}
}
@Subscribe
public void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
if(!ev.accountID.equals(accountID))
return;
if(ev.isUnfollow && !shouldRemoveAccountPostsWhenUnfollowing())
return;
StatusListFragment.this.onRemoveAccountPostsEvent(ev);
}
}
}

View File

@@ -1,6 +1,7 @@
package org.joinmastodon.android.fragments.discover;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
@@ -17,6 +18,7 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.fragments.ListTimelinesFragment;
@@ -29,6 +31,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.BaseRecyclerFragment;
import me.grishka.appkit.fragments.OnBackPressedListener;
@@ -58,6 +61,8 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
private String accountID;
private Runnable searchDebouncer=this::onSearchChangedDebounced;
private static final boolean noFederated = BuildConfig.BUILD_TYPE.equals("noFederatedRelease");
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -75,10 +80,11 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
tabLayout=view.findViewById(R.id.tabbar);
pager=view.findViewById(R.id.pager);
tabViews=new FrameLayout[7];
tabViews=new FrameLayout[noFederated ? 6 : 7];
for(int i=0;i<tabViews.length;i++){
FrameLayout tabView=new FrameLayout(getActivity());
tabView.setId(switch(i){
int switchIndex = noFederated && i > 0 ? i + 1 : i;
tabView.setId(switch(switchIndex){
case 0 -> R.id.discover_local_timeline;
case 1 -> R.id.discover_federated_timeline;
case 2 -> R.id.discover_hashtags;
@@ -86,7 +92,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
case 4 -> R.id.discover_news;
case 5 -> R.id.discover_users;
case 6 -> R.id.discover_lists;
default -> throw new IllegalStateException("Unexpected value: "+i);
default -> throw new IllegalStateException("Unexpected value: "+switchIndex);
});
tabView.setVisibility(View.GONE);
view.addView(tabView); // needed so the fragment manager will have somewhere to restore the tab fragment
@@ -131,26 +137,30 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
localTimelineFragment=new LocalTimelineFragment();
localTimelineFragment.setArguments(args);
federatedTimelineFragment=new FederatedTimelineFragment();
federatedTimelineFragment.setArguments(args);
listTimelinesFragment=new ListTimelinesFragment();
listTimelinesFragment.setArguments(args);
getChildFragmentManager().beginTransaction()
FragmentTransaction transaction = getChildFragmentManager().beginTransaction()
.add(R.id.discover_posts, postsFragment)
.add(R.id.discover_local_timeline, localTimelineFragment)
.add(R.id.discover_federated_timeline, federatedTimelineFragment)
.add(R.id.discover_hashtags, hashtagsFragment)
.add(R.id.discover_news, newsFragment)
.add(R.id.discover_users, accountsFragment)
.add(R.id.discover_lists, listTimelinesFragment)
.commit();
.add(R.id.discover_lists, listTimelinesFragment);
if (!noFederated) {
federatedTimelineFragment=new FederatedTimelineFragment();
federatedTimelineFragment.setArguments(args);
transaction.add(R.id.discover_federated_timeline, federatedTimelineFragment);
}
transaction.commit();
}
tabLayoutMediator=new TabLayoutMediator(tabLayout, pager, new TabLayoutMediator.TabConfigurationStrategy(){
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){
if (noFederated && position > 0) position++;
tab.setText(switch(position){
case 0 -> R.string.local_timeline;
case 1 -> R.string.federated_timeline;
@@ -280,6 +290,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
}
private Fragment getFragmentForPage(int page){
if (noFederated && page > 0) page++;
return switch(page){
case 0 -> localTimelineFragment;
case 1 -> federatedTimelineFragment;

View File

@@ -14,6 +14,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.ui.DividerItemDecoration;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
@@ -131,7 +132,10 @@ public class InstanceRulesFragment extends AppKitFragment{
@Override
public void onBind(Instance.Rule item){
title.setText(item.text);
if(item.parsedText==null){
item.parsedText=HtmlParser.parseLinks(item.text);
}
title.setText(item.parsedText);
}
}
}

View File

@@ -11,8 +11,10 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.fragments.MastodonToolbarFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Relationship;
@@ -130,6 +132,7 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
@Override
public void onSuccess(Relationship result){
Nav.finish(ReportDoneFragment.this);
E.post(new RemoveAccountPostsEvent(accountID, reportAccount.id, true));
}
@Override

View File

@@ -134,6 +134,8 @@ public class Instance extends BaseModel{
public static class Rule{
public String id;
public String text;
public transient CharSequence parsedText;
}
@Parcel

View File

@@ -0,0 +1,21 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import java.time.Instant;
@AllFieldsAreRequired
public class Marker extends BaseModel{
public String lastReadId;
public long version;
public Instant updatedAt;
@Override
public String toString(){
return "Marker{"+
"lastReadId='"+lastReadId+'\''+
", version="+version+
", updatedAt="+updatedAt+
'}';
}
}

View File

@@ -13,7 +13,7 @@ public class Poll extends BaseModel{
@RequiredField
public String id;
public Instant expiresAt;
public boolean expired;
private boolean expired;
public boolean multiple;
public int votersCount;
public boolean voted;
@@ -48,6 +48,10 @@ public class Poll extends BaseModel{
'}';
}
public boolean isExpired(){
return expired || (expiresAt!=null && expiresAt.isBefore(Instant.now()));
}
@Parcel
public static class Option{
public String title;

View File

@@ -130,6 +130,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
repliesCount=ev.replies;
favourited=ev.favorited;
reblogged=ev.reblogged;
bookmarked=ev.bookmarked;
pinned=ev.pinned;
}

View File

@@ -100,7 +100,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void bindButton(TextView btn, long count){
if(GlobalUserPreferences.showInteractionCounts && count>0 && !item.hideCounts){
btn.setText(DecimalFormat.getIntegerInstance().format(count));
btn.setText(UiUtils.abbreviateNumber(count));
btn.setCompoundDrawablePadding(V.dp(8));
}else{
btn.setText("");

View File

@@ -5,6 +5,7 @@ import android.app.ProgressDialog;
import android.graphics.Outline;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -209,6 +210,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
});
}else if(id==R.id.block_domain){
UiUtils.confirmToggleBlockDomain(activity, item.parentFragment.getAccountID(), account.getDomain(), relationship!=null && relationship.domainBlocking, ()->{});
}else if(id==R.id.bookmark){
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked);
}
return true;
});
@@ -226,6 +229,9 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
if(item.hasVisibilityToggle){
visibility.setImageResource(item.status.spoilerRevealed ? R.drawable.ic_visibility_off : R.drawable.ic_visibility);
visibility.setContentDescription(item.parentFragment.getString(item.status.spoilerRevealed ? R.string.hide_content : R.string.reveal_content));
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
visibility.setTooltipText(visibility.getContentDescription());
}
}
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
if(TextUtils.isEmpty(item.extraText)){
@@ -306,6 +312,16 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
MenuItem block=menu.findItem(R.id.block);
MenuItem report=menu.findItem(R.id.report);
MenuItem follow=menu.findItem(R.id.follow);
MenuItem bookmark=menu.findItem(R.id.bookmark);
bookmark.setVisible(false);
/* disabled in megalodon: add/remove bookmark is already available through status footer
if(item.status!=null){
bookmark.setVisible(true);
bookmark.setTitle(item.status.bookmarked ? R.string.remove_bookmark : R.string.add_bookmark);
}else{
bookmark.setVisible(false);
}
*/
if(isOwnPost){
mute.setVisible(false);
block.setVisible(false);

View File

@@ -38,13 +38,13 @@ public class PollFooterStatusDisplayItem extends StatusDisplayItem{
@Override
public void onBind(PollFooterStatusDisplayItem item){
String text=item.parentFragment.getResources().getQuantityString(R.plurals.x_voters, item.poll.votersCount, item.poll.votersCount);
if(item.poll.expiresAt!=null && !item.poll.expired){
if(item.poll.expiresAt!=null && !item.poll.isExpired()){
text+=" · "+UiUtils.formatTimeLeft(itemView.getContext(), item.poll.expiresAt);
}else if(item.poll.expired){
}else if(item.poll.isExpired()){
text+=" · "+item.parentFragment.getString(R.string.poll_closed);
}
this.text.setText(text);
button.setVisibility(item.poll.expired || item.poll.voted || !item.poll.multiple ? View.GONE : View.VISIBLE);
button.setVisibility(item.poll.isExpired() || item.poll.voted || !item.poll.multiple ? View.GONE : View.VISIBLE);
button.setEnabled(item.poll.selectedOptions!=null && !item.poll.selectedOptions.isEmpty());
}
}

View File

@@ -33,7 +33,7 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
this.poll=poll;
text=HtmlParser.parseCustomEmoji(option.title, poll.emojis);
emojiHelper.setText(text);
showResults=poll.expired || poll.voted;
showResults=poll.isExpired() || poll.voted;
if(showResults && option.votesCount!=null && poll.votersCount>0){
votesFraction=(float)option.votesCount/(float)poll.votersCount;
int mostVotedCount=0;

View File

@@ -2,8 +2,11 @@ package org.joinmastodon.android.ui.text;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.widget.TextView;
import com.twitter.twittertext.Regex;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.Mention;
@@ -28,6 +31,21 @@ import androidx.annotation.NonNull;
public class HtmlParser{
private static final String TAG="HtmlParser";
private static final String VALID_URL_PATTERN_STRING =
"(" + // $1 total match
"(" + Regex.URL_VALID_PRECEDING_CHARS + ")" + // $2 Preceding character
"(" + // $3 URL
"(https?://)" + // $4 Protocol (optional)
"(" + Regex.URL_VALID_DOMAIN + ")" + // $5 Domain(s)
"(?::(" + Regex.URL_VALID_PORT_NUMBER + "))?" + // $6 Port number (optional)
"(/" +
Regex.URL_VALID_PATH + "*+" +
")?" + // $7 URL Path and anchor
"(\\?" + Regex.URL_VALID_URL_QUERY_CHARS + "*" + // $8 Query String
Regex.URL_VALID_URL_QUERY_ENDING_CHARS + ")?" +
")" +
")";
public static final Pattern URL_PATTERN=Pattern.compile(VALID_URL_PATTERN_STRING, Pattern.CASE_INSENSITIVE);
private static Pattern EMOJI_CODE_PATTERN=Pattern.compile(":([\\w]+):");
private HtmlParser(){}
@@ -172,4 +190,18 @@ public class HtmlParser{
public static String strip(String html){
return Jsoup.clean(html, Safelist.none());
}
public static CharSequence parseLinks(String text){
Matcher matcher=URL_PATTERN.matcher(text);
if(!matcher.find()) // Return the original string if there are no URLs
return text;
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
do{
String url=matcher.group(3);
if(TextUtils.isEmpty(matcher.group(4)))
url="http://"+url;
ssb.setSpan(new LinkSpan(url, null, LinkSpan.Type.URL, null), matcher.start(3), matcher.end(3), 0);
}while(matcher.find()); // Find more URLs
return ssb;
}
}

View File

@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.view.Menu;
@@ -48,6 +49,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.FollowRequestHandledEvent;
import org.joinmastodon.android.events.NotificationDeletedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusDeletedEvent;
import org.joinmastodon.android.events.StatusUnpinnedEvent;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
@@ -345,6 +347,9 @@ public class UiUtils{
@Override
public void onSuccess(Relationship result){
resultCallback.accept(result);
if(!currentlyBlocked){
E.post(new RemoveAccountPostsEvent(accountID, account.id, false));
}
}
@Override
@@ -387,6 +392,9 @@ public class UiUtils{
@Override
public void onSuccess(Relationship result){
resultCallback.accept(result);
if(!currentlyMuted){
E.post(new RemoveAccountPostsEvent(accountID, account.id, false));
}
}
@Override
@@ -524,6 +532,9 @@ public class UiUtils{
public void onSuccess(Relationship result){
resultCallback.accept(result);
progressCallback.accept(false);
if(!result.following){
E.post(new RemoveAccountPostsEvent(accountID, account.id, true));
}
}
@Override
@@ -645,13 +656,71 @@ public class UiUtils{
}
public static void setUserPreferredTheme(Context context){
// boolean isDarkTheme = isDarkTheme();
switch(GlobalUserPreferences.color){
case PINK:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO -> GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack : R.style.Theme_Mastodon_AutoLightDark;
case LIGHT -> R.style.Theme_Mastodon_Light;
case DARK -> GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack : R.style.Theme_Mastodon_Dark;
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack : R.style.Theme_Mastodon_AutoLightDark;
case LIGHT ->
R.style.Theme_Mastodon_Light;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack : R.style.Theme_Mastodon_Dark;
});
break;
case PURPLE:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Original : R.style.Theme_Mastodon_AutoLightDark_Original;
case LIGHT ->
R.style.Theme_Mastodon_Light_Original;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Original : R.style.Theme_Mastodon_Dark_Original;
});
break;
case GREEN:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Green : R.style.Theme_Mastodon_AutoLightDark_Green;
case LIGHT ->
R.style.Theme_Mastodon_Light_Green;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Green : R.style.Theme_Mastodon_Dark_Green;
});
break;
case BLUE:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Blue : R.style.Theme_Mastodon_AutoLightDark_Blue;
case LIGHT ->
R.style.Theme_Mastodon_Light_Blue;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Blue : R.style.Theme_Mastodon_Dark_Blue;
});
break;
case ORANGE:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Orange : R.style.Theme_Mastodon_AutoLightDark_Orange;
case LIGHT ->
R.style.Theme_Mastodon_Light_Orange;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Orange : R.style.Theme_Mastodon_Dark_Orange;
});
break;
case YELLOW:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Yellow : R.style.Theme_Mastodon_AutoLightDark_Yellow;
case LIGHT ->
R.style.Theme_Mastodon_Light_Yellow;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Yellow : R.style.Theme_Mastodon_Dark_Yellow;
});
break;
}
}
public static boolean isDarkTheme(){
if(GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO)
return (MastodonApp.context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)==Configuration.UI_MODE_NIGHT_YES;
@@ -660,8 +729,7 @@ public class UiUtils{
public static void openURL(Context context, @Nullable String accountID, String url){
Uri uri=Uri.parse(url);
String accountDomain=accountID != null ? AccountSessionManager.getInstance().getAccount(accountID).domain : null;
if(accountDomain!=null && "https".equals(uri.getScheme()) && accountDomain.equalsIgnoreCase(uri.getAuthority())){
if(accountID!=null && "https".equals(uri.getScheme()) && AccountSessionManager.getInstance().getAccount(accountID).domain.equalsIgnoreCase(uri.getAuthority())){
List<String> path=uri.getPathSegments();
// Match URLs like https://mastodon.social/@Gargron/108132679274083591
if(path.size()==2 && path.get(0).matches("^@[a-zA-Z0-9_]+$") && path.get(1).matches("^[0-9]+$")){

View File

@@ -8,7 +8,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -22,7 +21,6 @@ import androidx.annotation.RequiresApi;
public class ComposeEditText extends EditText{
private SelectionListener selectionListener;
private MediaAcceptingInputConnection inputConnectionWrapper=new MediaAcceptingInputConnection();
public ComposeEditText(Context context){
super(context);
@@ -54,11 +52,10 @@ public class ComposeEditText extends EditText{
// Support receiving images from keyboards
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs){
final var ic = super.onCreateInputConnection(outAttrs);
final InputConnection ic=super.onCreateInputConnection(outAttrs);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N_MR1){
outAttrs.contentMimeTypes=selectionListener.onGetAllowedMediaMimeTypes();
inputConnectionWrapper.setTarget(ic);
return inputConnectionWrapper;
return new MediaAcceptingInputConnection(ic);
}
return ic;
}
@@ -106,8 +103,8 @@ public class ComposeEditText extends EditText{
}
private class MediaAcceptingInputConnection extends InputConnectionWrapper{
public MediaAcceptingInputConnection(){
super(null, true);
public MediaAcceptingInputConnection(InputConnection conn){
super(conn, false);
}
@RequiresApi(api=Build.VERSION_CODES.N_MR1)

View File

@@ -0,0 +1,70 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.V;
public class SplashLogoView extends ImageView{
private Bitmap shadow;
private Paint paint=new Paint();
public SplashLogoView(Context context){
this(context, null);
}
public SplashLogoView(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public SplashLogoView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
@Override
protected void onDraw(Canvas canvas){
if(shadow!=null){
paint.setColor(0xBF000000);
canvas.drawBitmap(shadow, 0, 0, paint);
}
super.onDraw(canvas);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh){
super.onSizeChanged(w, h, oldw, oldh);
if(w!=oldw || h!=oldh)
updateShadow();
}
@Override
public void setImageDrawable(@Nullable Drawable drawable){
super.setImageDrawable(drawable);
updateShadow();
}
private void updateShadow(){
int w=getWidth();
int h=getHeight();
Drawable drawable=getDrawable();
if(w==0 || h==0 || drawable==null)
return;
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
Bitmap temp=Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
shadow=Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
Canvas c=new Canvas(temp);
c.translate(getWidth()/2f-drawable.getIntrinsicWidth()/2f, getHeight()/2f-drawable.getIntrinsicHeight()/2f);
drawable.draw(c);
c=new Canvas(shadow);
Paint paint=new Paint();
paint.setShadowLayer(V.dp(2), 0, 0, 0xff000000);
c.drawBitmap(temp, 0, 0, paint);
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/boost_selected" android:state_selected="true"/>
<item android:color="?android:colorAccent" android:state_selected="true"/>
<item android:color="?android:textColorSecondary" android:state_enabled="true"/>
<item android:color="?android:textColorSecondary" android:alpha="0.3"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_800" android:state_enabled="true"/>
<item android:color="@color/gray_300"/>
<item android:color="?android:colorPrimary" android:state_enabled="true"/>
<item android:color="?colorPollVoted"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_100" android:state_enabled="true"/>
<item android:color="@color/gray_500"/>
<item android:color="?colorSecondary" android:state_enabled="true"/>
<item android:color="?colorPollVoted"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_25" android:state_enabled="true"/>
<item android:color="@color/gray_100"/>
<item android:color="?colorBackgroundLightest" android:state_enabled="true"/>
<item android:color="?android:colorBackground"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_600" android:state_enabled="true"/>
<item android:color="@color/gray_300"/>
<item android:color="?colorPollVoted" android:state_enabled="true"/>
<item android:color="?colorSearchHint"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_50" android:state_enabled="true"/>
<item android:color="@color/gray_400"/>
<item android:color="?colorSecondary" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_800" android:state_enabled="true"/>
<item android:color="@color/gray_400"/>
<item android:color="@color/black" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_800" android:state_enabled="true"/>
<item android:color="@color/gray_400"/>
<item android:color="?android:colorPrimary" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
</selector>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_50"/>
<item android:color="?colorSecondary"/>
</selector>

View File

@@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="0.9699526"
android:scaleY="0.9699526"
android:translateX="0.96"
android:translateY="6.925208">
<path
android:pathData="m3.639,-0c-1.097,0 -1.983,0.387 -2.658,1.141 -0.655,0.754 -0.981,1.771 -0.981,3.053l0,6.27L2.482,10.464L2.482,4.378c0,-1.284 0.539,-1.935 1.618,-1.935 1.192,0 1.791,0.773 1.791,2.3l0,3.331l2.468,0l0,-3.331c0,-1.527 0.598,-2.3 1.791,-2.3 1.078,0 1.618,0.651 1.618,1.935l0,6.085l2.482,0l0,-6.27c0,-1.281 -0.326,-2.299 -0.981,-3.053 -0.676,-0.754 -1.56,-1.141 -2.658,-1.141 -1.27,0 -2.232,0.488 -2.868,1.466L7.125,2.504 6.506,1.466C5.87,0.488 4.909,-0 3.639,-0Z"
android:strokeWidth="0.796"
android:fillColor="#000000"/>
<path
android:pathData="m18.947,10.464q-1.113,0 -1.986,-0.493 -0.873,-0.507 -1.366,-1.366 -0.479,-0.873 -0.479,-1.958 0,-1.07 0.479,-1.944 0.493,-0.873 1.366,-1.366 0.873,-0.507 1.986,-0.507 1.099,0 1.972,0.507 0.873,0.493 1.352,1.366 0.493,0.873 0.493,1.944 0,1.085 -0.493,1.958 -0.479,0.859 -1.352,1.366 -0.873,0.493 -1.972,0.493zM18.947,8.759q0.535,0 0.986,-0.254 0.451,-0.254 0.718,-0.732 0.268,-0.479 0.268,-1.127 0,-0.634 -0.268,-1.113 -0.268,-0.479 -0.718,-0.732 -0.451,-0.254 -0.986,-0.254 -0.535,0 -0.986,0.254 -0.451,0.254 -0.732,0.732 -0.268,0.479 -0.268,1.113 0,0.634 0.268,1.127 0.282,0.479 0.732,0.732 0.451,0.254 0.986,0.254z"
android:strokeWidth="0.687"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -2,7 +2,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/highlight_over_dark">
<item>
<shape android:shape="oval">
<solid android:color="@color/gray_600"/>
<solid android:color="?colorSearchHint"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.12 0.05,0.23 0.13,0.33 0.41,0.47 0.64,1.06 0.64,1.67 0,1.38 -1.12,2.5 -2.5,2.5zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5 0,-0.16 -0.08,-0.28 -0.14,-0.35 -0.41,-0.46 -0.63,-1.05 -0.63,-1.65 0,-1.38 1.12,-2.5 2.5,-2.5L16,15c2.21,0 4,-1.79 4,-4 0,-3.86 -3.59,-7 -8,-7z"/>
<path
android:fillColor="#FF000000"
android:pathData="M6.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M9.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M14.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M17.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
</vector>

View File

@@ -1,3 +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"/>
<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.748zm2.25-0.75c-0.414 0-0.75 0.336-0.75 0.75v13.196l4.873-2.842c0.233-0.137 0.522-0.137 0.755 0l4.873 2.842V6.748c0-0.414-0.336-0.75-0.75-0.75h-9zm9-3.998C17.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

@@ -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.53 12.97c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06l4.5 4.5c0.293 0.293 0.767 0.293 1.06 0l11-11c0.293-0.293 0.293-0.767 0-1.06-0.293-0.293-0.767-0.293-1.06 0L8.5 16.94l-3.97-3.97z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -4,7 +4,7 @@
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
<shape android:shape="oval">
<stroke android:color="?android:colorPrimary" android:width="2dp"/>
<solid android:color="@color/primary_600"/>
<solid android:color="?android:colorAccent"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="2.5091188"
android:scaleY="2.5091188">
<path
android:pathData="M0,0h43.043v43.043h-43.043z"
android:strokeWidth="1.53886"
android:fillColor="#282c37"/>
<path
android:pathData="m13.779,16.29c-1.097,0 -1.983,0.387 -2.658,1.141 -0.655,0.754 -0.981,1.771 -0.981,3.053l0,6.27L12.622,26.754L12.622,20.668c0,-1.284 0.539,-1.935 1.618,-1.935 1.192,0 1.791,0.773 1.791,2.3l0,3.331l2.468,0l0,-3.331c0,-1.527 0.598,-2.3 1.791,-2.3 1.078,0 1.618,0.651 1.618,1.935l0,6.085l2.482,0l0,-6.27c0,-1.281 -0.326,-2.299 -0.981,-3.053 -0.676,-0.754 -1.56,-1.141 -2.658,-1.141 -1.27,0 -2.232,0.488 -2.868,1.466L17.265,18.794 16.646,17.756C16.01,16.778 15.049,16.29 13.779,16.29Z"
android:strokeWidth="0.796"
android:fillColor="#eed7f4"/>
<path
android:pathData="m29.087,26.754q-1.113,0 -1.986,-0.493 -0.873,-0.507 -1.366,-1.366 -0.479,-0.873 -0.479,-1.958 0,-1.07 0.479,-1.944 0.493,-0.873 1.366,-1.366 0.873,-0.507 1.986,-0.507 1.099,0 1.972,0.507 0.873,0.493 1.352,1.366 0.493,0.873 0.493,1.944 0,1.085 -0.493,1.958 -0.479,0.859 -1.352,1.366 -0.873,0.493 -1.972,0.493zM29.087,25.049q0.535,0 0.986,-0.254 0.451,-0.254 0.718,-0.732 0.268,-0.479 0.268,-1.127 0,-0.634 -0.268,-1.113 -0.268,-0.479 -0.718,-0.732 -0.451,-0.254 -0.986,-0.254 -0.535,0 -0.986,0.254 -0.451,0.254 -0.732,0.732 -0.268,0.479 -0.268,1.113 0,0.634 0.268,1.127 0.282,0.479 0.732,0.732 0.451,0.254 0.986,0.254z"
android:strokeWidth="0.687"
android:fillColor="#eed7f4"
android:strokeColor="#00000000"/>
</group>
</vector>

View File

@@ -1,10 +0,0 @@
<vector android:height="24dp" android:viewportHeight="320"
android:viewportWidth="320" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group android:rotation="90" android:translateX="304" android:translateY="16" android:scaleX=".9" android:scaleY=".9">
<clip-path android:pathData="M0,0 0,320 320,320 320,0">
<path android:fillColor="#fff" android:pathData="M331.17,455.15c-0.9,-16.19 -2.47,-32.4 -4,-48.56 -0.18,-1.83 -0.35,-3.66 -0.53,-5.49 0,-0.4 -0.07,-0.79 -0.11,-1.19 -0.23,-2.39 -0.45,-4.79 -0.67,-7.18q-1.17,-12.75 -2.2,-25.6c-1,-12.83 -2,-25.72 -3,-38.63q-0.5,-6.45 -1,-12.91c-1.36,-17.23 -2.81,-34.48 -4.56,-51.69 -2.47,-24.15 -5.54,-48.22 -9.8,-72a13.13,13.13 0,0 0,-2 1c-18.27,11.86 -31.15,63.65 -38.89,82.19a2.7,2.7 0,0 1,-5.18 -0.79c-0.53,-5.37 -0.76,-10.78 -0.77,-16.2v-1.05a303.5,303.5 0,0 1,7.59 -65.79c4.46,-19.78 9.28,-44 23.15,-59.59 0.23,-0.26 1.83,-1.9 1.83,-1.9 -3,-14.17 -14.66,-42.19 -14.67,-42.2a136.07,136.07 0,0 0,-12.61 -25.07C242.82,29.09 204.46,0 166.47,0a70.43,70.43 0,0 0,-16.56 1.94c-39.17,9.42 -70.55,53.52 -88.75,87C40.69,126.5 29.93,168.34 20.1,209.72 5.32,271.87 -2.82,335.37 -8.77,398.91 -13.67,451.32 -30.7,510 22.87,541.51c24.5,14.41 53.18,23.56 81.15,28.16a213.92,213.92 0,0 0,34.86 2.51c10.31,0 20.64,-0.47 30.93,-0.95l108.72,-5c1.57,-0.07 3.2,-0.12 4.83,-0.12 8.69,0 17.78,1.42 22.39,8.4 0.55,-5.81 -4.53,-15.25 -10.6,-25.33l12.44,-2.81c0.31,-10 1.32,-17.53 5.46,-11.76 2,2.84 4.78,6 8.24,5.55 4.06,-0.49 5.79,-5.35 6.52,-9.37C332.36,505.83 332.59,480.52 331.17,455.15ZM168.3,538.52c-9.72,0.45 -19.77,0.91 -29.42,0.91a180.1,180.1 0,0 1,-29.54 -2.07C83.06,533 58.9,524.71 39.48,513.28c-12.37,-7.27 -18.39,-16 -20.79,-30 -2.74,-16 -0.24,-36.07 2.41,-57.29 1,-7.83 2,-15.93 2.74,-24C30.92,326.23 39.59,269.28 52,217.29c9.57,-40.22 19.67,-79.12 38,-112.74 21.38,-39.27 46.67,-65.73 67.64,-70.77a37.8,37.8 0,0 1,8.91 -1c14.5,0 31.71,7.73 47.22,21.2C228.67,67 240.3,83.72 245,99c-11.69,29.46 -22.95,68.57 -27.31,96.85C206,271.74 198.13,413.31 201.13,537Z"/>
<path android:fillColor="#fff" android:pathData="M177.15,182.12a30.01,18.34 97.5,1 0,7.83 -59.51a30.01,18.34 97.5,1 0,-7.83 59.51z"/>
<path android:fillColor="#fff" android:pathData="M0,320 320,320 288,288 32,288"/>
</clip-path>
</group>
</vector>

View File

@@ -4,7 +4,7 @@
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
<shape android:shape="oval">
<stroke android:color="?android:colorPrimary" android:width="2dp"/>
<solid android:color="@color/primary_600"/>
<solid android:color="?android:colorAccent"/>
</shape>
</item>
</layer-list>

View File

@@ -1,9 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="110dp"
android:height="18dp"
android:viewportWidth="110"
android:viewportHeight="18">
android:width="109.08dp"
android:height="18.02dp"
android:viewportWidth="109.08"
android:viewportHeight="18.02">
<path
android:pathData="M18.406,9.999V17.878H15.287V10.231C15.287,8.618 14.609,7.8 13.254,7.8C11.755,7.8 11.004,8.771 11.004,10.69V14.876H7.903V10.69C7.903,8.771 7.151,7.8 5.653,7.8C4.297,7.8 3.619,8.618 3.619,10.231V17.878H0.5V9.999C0.5,8.389 0.91,7.109 1.733,6.162C2.581,5.215 3.693,4.73 5.072,4.73C6.668,4.73 7.877,5.344 8.676,6.572L9.453,7.876L10.23,6.572C11.029,5.344 12.238,4.73 13.834,4.73C15.214,4.73 16.325,5.215 17.174,6.162C17.997,7.109 18.406,8.389 18.406,9.999ZM29.152,13.916C29.795,13.235 30.105,12.378 30.105,11.345C30.105,10.311 29.795,9.454 29.152,8.798C28.532,8.118 27.745,7.79 26.791,7.79C25.838,7.79 25.051,8.118 24.431,8.798C23.811,9.454 23.501,10.311 23.501,11.345C23.501,12.378 23.811,13.235 24.431,13.916C25.051,14.571 25.838,14.899 26.791,14.899C27.745,14.899 28.532,14.571 29.152,13.916ZM30.105,5.042H33.181V17.647H30.105V16.16C29.176,17.395 27.888,18 26.219,18C24.622,18 23.263,17.37 22.118,16.084C20.998,14.798 20.426,13.21 20.426,11.345C20.426,9.504 20.998,7.916 22.118,6.63C23.263,5.345 24.622,4.689 26.219,4.689C27.888,4.689 29.176,5.294 30.105,6.529V5.042ZM43.528,11.118C44.434,11.798 44.888,12.756 44.864,13.966C44.864,15.252 44.41,16.26 43.481,16.966C42.551,17.647 41.431,18 40.072,18C37.616,18 35.947,16.992 35.065,15L37.735,13.412C38.093,14.496 38.879,15.05 40.072,15.05C41.168,15.05 41.717,14.697 41.717,13.966C41.717,13.437 41.001,12.958 39.547,12.58C38.999,12.429 38.546,12.277 38.188,12.151C37.688,11.95 37.258,11.723 36.901,11.445C36.019,10.765 35.566,9.857 35.566,8.698C35.566,7.462 35.995,6.479 36.853,5.773C37.735,5.042 38.808,4.689 40.095,4.689C42.146,4.689 43.648,5.571 44.625,7.361L42.003,8.874C41.621,8.017 40.978,7.588 40.095,7.588C39.166,7.588 38.713,7.941 38.713,8.622C38.713,9.151 39.428,9.63 40.882,10.008C42.003,10.26 42.885,10.639 43.528,11.118ZM53.304,8.168H50.61V13.412C50.61,14.042 50.848,14.42 51.301,14.597C51.635,14.723 52.303,14.748 53.304,14.697V17.647C51.23,17.899 49.728,17.698 48.846,17.017C47.964,16.361 47.534,15.151 47.534,13.412V8.168H45.46V5.042H47.534V2.496L50.61,1.513V5.042H53.304V8.168ZM63.103,13.84C63.723,13.185 64.033,12.353 64.033,11.344C64.033,10.336 63.723,9.504 63.103,8.849C62.483,8.193 61.721,7.866 60.791,7.866C59.861,7.866 59.098,8.193 58.478,8.849C57.882,9.529 57.572,10.361 57.572,11.344C57.572,12.328 57.882,13.16 58.478,13.84C59.098,14.496 59.861,14.823 60.791,14.823C61.721,14.823 62.483,14.496 63.103,13.84ZM56.308,16.084C55.093,14.798 54.497,13.235 54.497,11.344C54.497,9.479 55.093,7.916 56.308,6.63C57.524,5.345 59.026,4.689 60.791,4.689C62.555,4.689 64.057,5.345 65.273,6.63C66.489,7.916 67.109,9.504 67.109,11.344C67.109,13.21 66.489,14.798 65.273,16.084C64.057,17.37 62.579,18 60.791,18C59.002,18 57.524,17.37 56.308,16.084ZM77.385,13.916C78.005,13.235 78.314,12.378 78.314,11.345C78.314,10.311 78.005,9.454 77.385,8.798C76.765,8.118 75.978,7.79 75.024,7.79C74.071,7.79 73.284,8.118 72.64,8.798C72.021,9.454 71.71,10.311 71.71,11.345C71.71,12.378 72.021,13.235 72.64,13.916C73.284,14.571 74.094,14.899 75.024,14.899C75.978,14.899 76.765,14.571 77.385,13.916ZM78.314,0H81.39V17.647H78.314V16.16C77.409,17.395 76.121,18 74.452,18C72.855,18 71.472,17.37 70.328,16.084C69.207,14.798 68.635,13.21 68.635,11.345C68.635,9.504 69.207,7.916 70.328,6.63C71.472,5.345 72.855,4.689 74.452,4.689C76.121,4.689 77.409,5.294 78.314,6.529V0ZM92.191,13.84C92.811,13.185 93.12,12.353 93.12,11.344C93.12,10.336 92.811,9.504 92.191,8.849C91.571,8.193 90.808,7.866 89.878,7.866C88.948,7.866 88.185,8.193 87.565,8.849C86.969,9.529 86.659,10.361 86.659,11.344C86.659,12.328 86.969,13.16 87.565,13.84C88.185,14.496 88.948,14.823 89.878,14.823C90.808,14.823 91.571,14.496 92.191,13.84ZM85.396,16.084C84.18,14.798 83.584,13.235 83.584,11.344C83.584,9.479 84.18,7.916 85.396,6.63C86.612,5.345 88.114,4.689 89.878,4.689C91.642,4.689 93.144,5.345 94.36,6.63C95.576,7.916 96.196,9.504 96.196,11.344C96.196,13.21 95.576,14.798 94.36,16.084C93.144,17.37 91.666,18 89.878,18C88.09,18 86.612,17.37 85.396,16.084ZM109.5,9.908V17.647H106.424V10.311C106.424,9.479 106.21,8.849 105.781,8.37C105.375,7.941 104.803,7.714 104.064,7.714C102.324,7.714 101.442,8.748 101.442,10.84V17.647H98.366V5.042H101.442V6.454C102.181,5.269 103.349,4.689 104.994,4.689C106.305,4.689 107.378,5.143 108.213,6.076C109.071,7.009 109.5,8.269 109.5,9.908Z"
android:fillColor="#282C37"/>
android:pathData="m26.28,18.02q-1.9,0 -3.38,-0.84 -1.49,-0.86 -2.33,-2.33 -0.82,-1.49 -0.82,-3.34 0,-1.82 0.82,-3.31 0.84,-1.49 2.33,-2.33 1.49,-0.86 3.38,-0.86 1.87,0 3.36,0.86 1.49,0.84 2.3,2.33 0.84,1.49 0.84,3.31 0,1.85 -0.84,3.34 -0.82,1.46 -2.3,2.33 -1.49,0.84 -3.36,0.84zM26.28,15.12q0.91,0 1.68,-0.43 0.77,-0.43 1.22,-1.25 0.46,-0.82 0.46,-1.92 0,-1.08 -0.46,-1.9 -0.46,-0.82 -1.22,-1.25 -0.77,-0.43 -1.68,-0.43 -0.91,0 -1.68,0.43 -0.77,0.43 -1.25,1.25 -0.46,0.82 -0.46,1.9 0,1.08 0.46,1.92 0.48,0.82 1.25,1.25 0.77,0.43 1.68,0.43z"
android:fillColor="#282c37"/>
<path
android:pathData="m39.72,18.02q-2.23,0 -3.62,-0.91 -1.37,-0.91 -1.92,-2.38l2.81,-1.22q0.38,0.86 1.08,1.32 0.72,0.43 1.66,0.43 0.86,0 1.44,-0.26 0.58,-0.29 0.58,-0.91 0,-0.6 -0.53,-0.89 -0.53,-0.31 -1.58,-0.55l-1.44,-0.31q-1.49,-0.36 -2.47,-1.3 -0.98,-0.96 -0.98,-2.38 0,-1.06 0.62,-1.9 0.65,-0.84 1.73,-1.3 1.1,-0.46 2.42,-0.46 3.79,0 5.06,2.66l-2.69,1.18q-0.72,-1.3 -2.3,-1.3 -0.82,0 -1.3,0.31 -0.48,0.29 -0.48,0.74 0,0.86 1.63,1.3l1.8,0.43q1.82,0.46 2.74,1.39 0.94,0.94 0.94,2.3 0,1.18 -0.7,2.09 -0.67,0.89 -1.87,1.39 -1.18,0.5 -2.62,0.5z"
android:fillColor="#282c37"/>
<path
android:pathData="m47.19,0.46h3.14L50.33,4.8l-0.19,2.14h0.19q0.53,-0.86 1.54,-1.39 1.01,-0.53 2.18,-0.53 2.23,0 3.41,1.34 1.2,1.32 1.2,3.67v7.61h-3.14v-7.22q0,-1.18 -0.65,-1.82 -0.62,-0.65 -1.68,-0.65 -1.25,0 -2.06,1.01 -0.79,1.01 -0.79,2.47v6.22h-3.14z"
android:fillColor="#282c37"/>
<path
android:pathData="m63.41,4.06q-0.84,0 -1.44,-0.6 -0.6,-0.6 -0.6,-1.44 0,-0.84 0.6,-1.42 0.6,-0.6 1.44,-0.6 0.84,0 1.42,0.6 0.6,0.58 0.6,1.42 0,0.84 -0.6,1.44 -0.58,0.6 -1.42,0.6zM61.83,5.4h3.14L64.97,17.64h-3.14z"
android:fillColor="#282c37"/>
<path
android:pathData="m73.39,18.02q-1.66,0 -3.02,-0.82 -1.34,-0.84 -2.14,-2.3 -0.77,-1.49 -0.77,-3.38 0,-1.87 0.77,-3.36 0.79,-1.49 2.14,-2.3 1.37,-0.84 3.02,-0.84 1.25,0 2.21,0.55 0.96,0.53 1.46,1.32h0.19l-0.19,-1.73L77.07,0.46h3.12L80.19,17.64h-2.93v-1.46h-0.19q-0.48,0.79 -1.46,1.32 -0.96,0.53 -2.21,0.53zM73.92,15.12q0.89,0 1.66,-0.46 0.77,-0.46 1.22,-1.27 0.46,-0.82 0.46,-1.87 0,-1.06 -0.46,-1.87 -0.46,-0.82 -1.22,-1.25 -0.77,-0.46 -1.66,-0.46 -0.86,0 -1.63,0.46 -0.77,0.43 -1.22,1.25 -0.46,0.82 -0.46,1.87 0,1.06 0.46,1.87 0.46,0.82 1.22,1.27 0.77,0.46 1.63,0.46z"
android:fillColor="#282c37"/>
<path
android:pathData="m89.02,18.02q-1.9,0 -3.38,-0.84 -1.49,-0.86 -2.33,-2.33 -0.82,-1.49 -0.82,-3.34 0,-1.82 0.82,-3.31 0.84,-1.49 2.33,-2.33 1.49,-0.86 3.38,-0.86 1.87,0 3.36,0.86 1.49,0.84 2.3,2.33 0.84,1.49 0.84,3.31 0,1.85 -0.84,3.34 -0.82,1.46 -2.3,2.33 -1.49,0.84 -3.36,0.84zM89.02,15.12q0.91,0 1.68,-0.43 0.77,-0.43 1.22,-1.25 0.46,-0.82 0.46,-1.92 0,-1.08 -0.46,-1.9 -0.46,-0.82 -1.22,-1.25 -0.77,-0.43 -1.68,-0.43 -0.91,0 -1.68,0.43 -0.77,0.43 -1.25,1.25 -0.46,0.82 -0.46,1.9 0,1.08 0.46,1.92 0.48,0.82 1.25,1.25 0.77,0.43 1.68,0.43z"
android:fillColor="#282c37"/>
<path
android:pathData="m97.68,5.4h2.95v1.54h0.19q0.55,-0.89 1.56,-1.39 1.01,-0.53 2.18,-0.53 2.21,0 3.36,1.34 1.15,1.34 1.15,3.67v7.61h-3.14v-7.22q0,-1.18 -0.6,-1.82 -0.6,-0.65 -1.68,-0.65 -1.27,0 -2.06,0.98 -0.77,0.98 -0.77,2.47v6.24h-3.14z"
android:fillColor="#282c37"/>
<path
android:pathData="m4.53,5c-1.37,0 -2.47,0.48 -3.31,1.42C0.41,7.35 0,8.62 0,10.21v7.8h3.09v-7.57c0,-1.6 0.67,-2.41 2.01,-2.41 1.48,0 2.23,0.96 2.23,2.86v4.14h3.07v-4.14c0,-1.9 0.74,-2.86 2.23,-2.86 1.34,0 2.01,0.81 2.01,2.41v7.57h3.09v-7.8c0,-1.59 -0.41,-2.86 -1.22,-3.8 -0.84,-0.94 -1.94,-1.42 -3.31,-1.42 -1.58,0 -2.78,0.61 -3.57,1.82l-0.77,1.29 -0.77,-1.29C7.3,5.6 6.11,5 4.53,5Z"
android:strokeWidth="0.990258"
android:fillColor="#282c37"/>
</vector>

View File

@@ -2,7 +2,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<stroke android:color="@color/gray_50" android:width="4dp"/>
<stroke android:color="?colorSecondary" android:width="4dp"/>
<solid android:color="#80000000"/>
<size android:width="52dp" android:height="52dp"/>
</shape>

View File

@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="257dp"
android:height="67dp"
android:viewportWidth="313"
android:viewportHeight="81">
<path
android:pathData="M72.95,18.45C71.82,9.95 64.5,3.24 55.85,1.95C54.38,1.73 48.85,0.93 36.02,0.93H35.92C23.09,0.93 20.34,1.73 18.87,1.95C10.44,3.22 2.76,9.23 0.88,17.84C-0,22.08 -0.1,26.78 0.07,31.09C0.31,37.27 0.36,43.43 0.91,49.6C1.29,53.69 1.95,57.74 2.9,61.73C4.68,69.11 11.86,75.25 18.9,77.75C26.43,80.35 34.53,80.79 42.29,79C43.14,78.79 43.98,78.56 44.82,78.29C46.71,77.68 48.92,77 50.55,75.81C50.57,75.8 50.59,75.77 50.6,75.75C50.61,75.72 50.62,75.7 50.62,75.66V69.7C50.62,69.7 50.62,69.65 50.6,69.62C50.6,69.6 50.57,69.58 50.55,69.56C50.53,69.55 50.5,69.54 50.48,69.53C50.45,69.53 50.43,69.53 50.41,69.53C45.43,70.73 40.33,71.34 35.23,71.33C26.43,71.33 24.06,67.09 23.39,65.34C22.85,63.82 22.5,62.22 22.36,60.61C22.36,60.59 22.36,60.57 22.37,60.54C22.37,60.52 22.39,60.49 22.42,60.48C22.44,60.47 22.46,60.46 22.49,60.44H22.57C27.46,61.64 32.48,62.25 37.51,62.25C38.72,62.25 39.92,62.25 41.14,62.21C46.19,62.06 51.52,61.81 56.51,60.82C56.63,60.8 56.76,60.77 56.87,60.75C64.72,59.21 72.19,54.42 72.95,42.27C72.97,41.79 73.04,37.25 73.04,36.76C73.04,35.07 73.58,24.79 72.96,18.48L72.95,18.45Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="36.62"
android:startY="0.93"
android:endX="36.62"
android:endY="80.07"
android:type="linear">
<item android:offset="0" android:color="#FF6364FF"/>
<item android:offset="1" android:color="#FF563ACC"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M14.81,23.2C14.81,20.72 16.77,18.72 19.2,18.72C21.62,18.72 23.58,20.73 23.58,23.2C23.58,25.67 21.62,27.68 19.2,27.68C16.77,27.68 14.81,25.67 14.81,23.2Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M80.02,27.06V47.66H72.03V27.67C72.03,23.45 70.3,21.32 66.83,21.32C63,21.32 61.07,23.87 61.07,28.87V39.82H53.14V28.87C53.14,23.84 51.24,21.32 47.38,21.32C43.92,21.32 42.18,23.45 42.18,27.67V47.65H34.21V27.06C34.21,22.86 35.25,19.51 37.35,17.03C39.53,14.54 42.37,13.29 45.89,13.29C49.97,13.29 53.07,14.9 55.11,18.11L57.11,21.52L59.1,18.11C61.14,14.91 64.23,13.29 68.32,13.29C71.84,13.29 74.69,14.55 76.86,17.03C78.96,19.51 80.01,22.83 80.01,27.06H80.02ZM107.49,37.3C109.15,35.51 109.93,33.29 109.93,30.59C109.93,27.89 109.14,25.65 107.49,23.94C105.91,22.15 103.89,21.3 101.45,21.3C99.02,21.3 97.01,22.15 95.41,23.94C93.83,25.65 93.04,27.89 93.04,30.59C93.04,33.29 93.83,35.53 95.41,37.3C97,39 99.02,39.87 101.45,39.87C103.89,39.87 105.9,39.02 107.49,37.3ZM109.93,14.12H117.8V47.06H109.93V43.18C107.55,46.41 104.26,48 99.99,48C95.71,48 92.42,46.36 89.5,43C86.64,39.64 85.18,35.48 85.18,30.61C85.18,25.74 86.65,21.65 89.5,18.29C92.43,14.93 95.92,13.23 99.99,13.23C104.06,13.23 107.55,14.81 109.93,18.02V14.14V14.12ZM144.26,29.97C146.58,31.76 147.73,34.25 147.67,37.41C147.67,40.77 146.52,43.41 144.14,45.24C141.76,47.03 138.89,47.94 135.41,47.94C129.13,47.94 124.87,45.3 122.61,40.11L129.43,35.96C130.34,38.78 132.35,40.25 135.41,40.25C138.22,40.25 139.62,39.33 139.62,37.42C139.62,36.03 137.79,34.78 134.07,33.8C132.66,33.41 131.5,33.01 130.6,32.68C129.31,32.16 128.22,31.56 127.31,30.83C125.05,29.04 123.9,26.68 123.9,23.65C123.9,20.42 124.99,17.85 127.19,16C129.45,14.09 132.19,13.18 135.48,13.18C140.73,13.18 144.56,15.48 147.07,20.16L140.37,24.1C139.4,21.86 137.74,20.74 135.48,20.74C133.11,20.74 131.95,21.65 131.95,23.44C131.95,24.83 133.78,26.08 137.5,27.06C140.37,27.72 142.63,28.7 144.26,29.97H144.27H144.26ZM169.26,22.27H162.37V35.98C162.37,37.63 162.98,38.63 164.15,39.08C165,39.4 166.71,39.47 169.27,39.34V47.05C163.98,47.71 160.14,47.17 157.88,45.41C155.62,43.7 154.53,40.53 154.53,36V22.27H149.23V14.1H154.53V7.46L162.39,4.89V14.12H169.29V22.29H169.27L169.26,22.27ZM194.34,37.1C195.92,35.4 196.71,33.22 196.71,30.58C196.71,27.94 195.92,25.78 194.34,24.05C192.74,22.35 190.79,21.48 188.42,21.48C186.04,21.48 184.09,22.33 182.49,24.05C180.97,25.84 180.18,28 180.18,30.58C180.18,33.16 180.97,35.31 182.49,37.1C184.08,38.81 186.04,39.67 188.42,39.67C190.79,39.67 192.74,38.82 194.34,37.1ZM176.96,42.96C173.85,39.6 172.32,35.52 172.32,30.58C172.32,25.63 173.85,21.62 176.96,18.26C180.07,14.9 183.91,13.19 188.42,13.19C192.92,13.19 196.77,14.9 199.87,18.26C202.97,21.62 204.57,25.77 204.57,30.58C204.57,35.39 202.97,39.6 199.87,42.96C196.76,46.32 192.98,47.96 188.42,47.96C183.85,47.96 180.06,46.32 176.96,42.96ZM230.86,37.29C232.45,35.5 233.24,33.28 233.24,30.58C233.24,27.87 232.45,25.63 230.86,23.93C229.28,22.14 227.26,21.29 224.82,21.29C222.39,21.29 220.37,22.14 218.73,23.93C217.14,25.63 216.35,27.87 216.35,30.58C216.35,33.28 217.14,35.52 218.73,37.29C220.38,38.99 222.45,39.86 224.82,39.86C227.2,39.86 229.27,39 230.86,37.29ZM233.24,0.92H241.11V47.05H233.24V43.17C230.93,46.39 227.63,47.99 223.36,47.99C219.09,47.99 215.75,46.35 212.8,42.98C209.93,39.62 208.48,35.47 208.48,30.6C208.48,25.73 209.95,21.64 212.8,18.28C215.72,14.92 219.26,13.22 223.36,13.22C227.45,13.22 230.93,14.8 233.24,18.01V0.93V0.92ZM268.74,37.07C270.32,35.36 271.12,33.18 271.12,30.54C271.12,27.9 270.32,25.74 268.74,24.01C267.15,22.31 265.21,21.45 262.82,21.45C260.43,21.45 258.5,22.3 256.9,24.01C255.37,25.8 254.58,27.96 254.58,30.54C254.58,33.12 255.37,35.28 256.9,37.07C258.48,38.77 260.44,39.64 262.82,39.64C265.2,39.64 267.14,38.78 268.74,37.07ZM251.36,42.92C248.26,39.56 246.73,35.48 246.73,30.54C246.73,25.6 248.25,21.58 251.36,18.22C254.47,14.86 258.32,13.15 262.82,13.15C267.32,13.15 271.18,14.86 274.27,18.22C277.38,21.58 278.97,25.73 278.97,30.54C278.97,35.35 277.38,39.56 274.27,42.92C271.16,46.28 267.38,47.93 262.82,47.93C258.26,47.93 254.46,46.28 251.36,42.92ZM313,26.78V47.01H305.14V27.84C305.14,25.66 304.59,24.01 303.48,22.77C302.45,21.65 300.98,21.07 299.09,21.07C294.65,21.07 292.39,23.77 292.39,29.24V47.03H284.53V14.1H292.39V17.81C294.28,14.71 297.28,13.19 301.47,13.19C304.82,13.19 307.57,14.37 309.71,16.81C311.91,19.24 313,22.54 313,26.82"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -35,16 +35,18 @@
android:id="@+id/reply_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="-12dp"
android:paddingHorizontal="16dp"
android:paddingTop="16dp"
android:paddingBottom="6dp"
android:textAppearance="@style/m3_title_small"
android:drawableStart="@drawable/ic_fluent_arrow_reply_20_filled"
tools:drawableEnd="@drawable/ic_fluent_earth_20_regular"
android:drawableTint="?android:textColorSecondary"
android:drawablePadding="6dp"
android:singleLine="true"
android:ellipsize="end"/>
android:ellipsize="end"
android:background="?android:selectableItemBackground"/>
<RelativeLayout
android:layout_width="match_parent"
@@ -212,6 +214,7 @@
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/add_media"
android:tooltipText="@string/add_media"
android:src="@drawable/ic_fluent_image_24_regular"/>
<ImageButton
@@ -224,6 +227,7 @@
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/add_poll"
android:tooltipText="@string/add_poll"
android:src="@drawable/ic_fluent_poll_24_selector"/>
<ImageButton
@@ -236,6 +240,7 @@
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/emoji"
android:tooltipText="@string/emoji"
android:src="@drawable/ic_fluent_emoji_24_selector"/>
<ImageButton
@@ -248,6 +253,7 @@
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/content_warning"
android:tooltipText="@string/content_warning"
android:src="@drawable/ic_fluent_chat_warning_24_selector"/>
<ImageButton
@@ -260,6 +266,7 @@
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/post_visibility"
android:tooltipText="@string/post_visibility"
android:src="@drawable/ic_fluent_earth_24_regular"/>
<Space

View File

@@ -73,11 +73,13 @@
android:transformPivotY="1px"
android:background="#478E6A"/>
<ImageView
<org.joinmastodon.android.ui.views.SplashLogoView
android:layout_width="261dp"
android:layout_height="67dp"
android:layout_height="71dp"
android:layout_gravity="center_horizontal|top"
android:layout_marginTop="24dp"
android:scaleType="center"
android:importantForAccessibility="no"
android:src="@drawable/splash_logo"/>
<LinearLayout

View File

@@ -14,7 +14,7 @@
android:tint="?android:textColorSecondary"
android:src="@drawable/ic_round_checkbox"/>
<TextView
<org.joinmastodon.android.ui.views.LinkedTextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout 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="48dp"
android:gravity="center_vertical"
android:layoutDirection="locale">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="32dp"
android:importantForAccessibility="no"
android:tint="?android:textColorPrimary"
tools:src="@drawable/ic_color_theme_preference"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:textColor="?android:textColorPrimary"
android:textSize="16sp"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/settings_color_picker"/>
<Button
android:id="@+id/color_picker_button"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:background="@drawable/bg_inline_button"
android:elevation="0dp"
android:ellipsize="middle"
android:fontFamily="sans-serif-medium"
android:singleLine="true"
android:stateListAnimator="@null"
android:textColor="?android:textColorPrimary"
android:textSize="16sp"
tools:text="@string/pink_color" />
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/purple_color" android:title="@string/purple_color"/>
<item android:id="@+id/pink_color" android:title="@string/pink_color"/>
<item android:id="@+id/green_color" android:title="@string/green_color"/>
<item android:id="@+id/blue_color" android:title="@string/blue_color"/>
<item android:id="@+id/orange_color" android:title="@string/orange_color"/>
<item android:id="@+id/yellow_color" android:title="@string/yellow_color"/>
</menu>

View File

@@ -10,5 +10,6 @@
<item android:id="@+id/block_domain" android:title="@string/block_domain"/>
<item android:id="@+id/follow" android:title="@string/follow_user"/>
<item android:id="@+id/report" android:title="@string/report_user"/>
<item android:id="@+id/bookmark" android:title="@string/add_bookmark"/>
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser"/>
</menu>

View File

@@ -8,11 +8,4 @@
<item android:id="@+id/hide_boosts" android:title="@string/hide_boosts_from_user"/>
<item android:id="@+id/manage_user_lists" android:title="@string/lists_with_user"/>
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser"/>
<item android:id="@+id/favorites_list" android:title="@string/favorited_posts" android:visible="false"/>
<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,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/bookmarks" android:title="@string/bookmarks" android:icon="@drawable/ic_fluent_bookmark_multiple_24_regular" android:showAsAction="always"/>
<item android:id="@+id/favorites" android:title="@string/your_favorites" android:icon="@drawable/ic_fluent_star_24_regular"/>
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/>
</menu>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
<background android:drawable="@color/shortcut_icon_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
<background android:drawable="@color/shortcut_icon_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Some files were not shown because too many files have changed in this diff Show More