diff --git a/mastodon/src/main/AndroidManifest.xml b/mastodon/src/main/AndroidManifest.xml
index 54255565b..b648d1445 100644
--- a/mastodon/src/main/AndroidManifest.xml
+++ b/mastodon/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
diff --git a/mastodon/src/main/java/org/joinmastodon/android/MainActivity.java b/mastodon/src/main/java/org/joinmastodon/android/MainActivity.java
index 7aea868fd..7e9bf6e34 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/MainActivity.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/MainActivity.java
@@ -1,20 +1,28 @@
package org.joinmastodon.android;
+import static org.joinmastodon.android.fragments.ComposeFragment.CAMERA_PERMISSION_CODE;
+import static org.joinmastodon.android.fragments.ComposeFragment.CAMERA_PIC_REQUEST_CODE;
+
import android.Manifest;
+import android.app.Activity;
import android.app.Fragment;
import android.app.assist.AssistContent;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.Toast;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
+import org.joinmastodon.android.events.PictureTakenEvent;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
@@ -189,6 +197,27 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
}
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data){
+ if(requestCode==CAMERA_PIC_REQUEST_CODE && resultCode== Activity.RESULT_OK){
+ Bitmap image = (Bitmap) data.getExtras().get("data");
+ String path = MediaStore.Images.Media.insertImage(this.getContentResolver(), image, null, null);
+ E.post(new PictureTakenEvent(Uri.parse(path)));
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ if (requestCode == CAMERA_PERMISSION_CODE && (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST_CODE);
+ } else {
+ Toast.makeText(this, R.string.permission_required, Toast.LENGTH_SHORT);
+ }
+ }
+
public Fragment getCurrentFragment() {
for (int i = fragmentContainers.size() - 1; i >= 0; i--) {
FrameLayout fl = fragmentContainers.get(i);
diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/PictureTakenEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/PictureTakenEvent.java
new file mode 100644
index 000000000..80d1e1ce9
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/events/PictureTakenEvent.java
@@ -0,0 +1,13 @@
+package org.joinmastodon.android.events;
+
+import android.net.Uri;
+
+import org.joinmastodon.android.model.Poll;
+
+public class PictureTakenEvent {
+ public Uri uri;
+
+ public PictureTakenEvent(Uri uri){
+ this.uri = uri;
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
index fd9afde61..c52d9fbfd 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
@@ -1,7 +1,5 @@
package org.joinmastodon.android.fragments;
-import static android.os.ext.SdkExtensions.getExtensionVersion;
-
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT;
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant;
@@ -9,6 +7,7 @@ import static org.joinmastodon.android.ui.utils.UiUtils.isPhotoPickerAvailable;
import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages;
+import android.Manifest;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -17,6 +16,7 @@ import android.app.TimePickerDialog;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -29,7 +29,6 @@ import android.graphics.drawable.LayerDrawable;
import android.icu.text.BreakIterator;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
-import android.opengl.Visibility;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
@@ -70,7 +69,10 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+
import com.github.bottomSoftwareFoundation.bottom.Bottom;
+import com.squareup.otto.Subscribe;
import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E;
@@ -87,11 +89,14 @@ import org.joinmastodon.android.api.requests.statuses.GetAttachmentByID;
import org.joinmastodon.android.api.requests.statuses.UploadAttachment;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
+import org.joinmastodon.android.events.PictureTakenEvent;
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
+import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusUpdatedEvent;
+import org.joinmastodon.android.fragments.settings.SettingsBaseFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.ContentType;
@@ -113,6 +118,7 @@ import org.joinmastodon.android.ui.text.ComposeAutocompleteSpan;
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
+import org.joinmastodon.android.updater.GithubSelfUpdater;
import org.joinmastodon.android.utils.TransferSpeedTracker;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ComposeEditText;
@@ -161,6 +167,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private static final String GLITCH_LOCAL_ONLY_SUFFIX = "👁";
private static final Pattern GLITCH_LOCAL_ONLY_PATTERN = Pattern.compile("[\\s\\S]*" + GLITCH_LOCAL_ONLY_SUFFIX + "[\uFE00-\uFE0F]*");
private static final String TAG="ComposeFragment";
+ public static final int CAMERA_PERMISSION_CODE = 626938;
+ public static final int CAMERA_PIC_REQUEST_CODE = 6242069;
public static final Pattern MENTION_PATTERN=Pattern.compile("(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)", Pattern.CASE_INSENSITIVE);
@@ -246,6 +254,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
+ E.register(this);
setRetainInstance(true);
navigationBarColorBefore = getActivity().getWindow().getNavigationBarColor();
getActivity().getWindow().setNavigationBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLightest));
@@ -286,6 +295,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override
public void onDestroy(){
super.onDestroy();
+ E.unregister(this);
for(DraftMediaAttachment att:attachments){
if(att.isUploadingOrProcessing())
att.cancelUpload();
@@ -365,19 +375,28 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
view.findViewById(GlobalUserPreferences.replyLineAboveHeader ? R.id.reply_text_below : R.id.reply_text)
.setVisibility(View.GONE);
- if (isPhotoPickerAvailable()) {
- PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
- attachPopup.inflate(R.menu.attach);
- attachPopup.setOnMenuItemClickListener(i -> {
+ PopupMenu attachPopup = new PopupMenu(getContext(), mediaBtn);
+ attachPopup.inflate(R.menu.attach);
+ if(isPhotoPickerAvailable())
+ attachPopup.getMenu().findItem(R.id.media).setVisible(true);
+
+ attachPopup.setOnMenuItemClickListener(i -> {
+ if (i.getItemId() == R.id.camera){
+ if (getContext().checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
+ Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST_CODE);
+ } else {
+ getActivity().requestPermissions(new String[] { Manifest.permission.CAMERA }, CAMERA_PERMISSION_CODE);
+ }
+
+ } else {
openFilePicker(i.getItemId() == R.id.media);
- return true;
- });
- UiUtils.enablePopupMenuIcons(getContext(), attachPopup);
- mediaBtn.setOnClickListener(v->attachPopup.show());
- mediaBtn.setOnTouchListener(attachPopup.getDragToOpenListener());
- } else {
- mediaBtn.setOnClickListener(v -> openFilePicker(false));
- }
+ }
+ return true;
+ });
+ UiUtils.enablePopupMenuIcons(getContext(), attachPopup);
+ mediaBtn.setOnClickListener(v->attachPopup.show());
+ mediaBtn.setOnTouchListener(attachPopup.getDragToOpenListener());
if (isInstancePixelfed()) pollBtn.setVisibility(View.GONE);
pollBtn.setOnClickListener(v->togglePoll());
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
@@ -569,6 +588,19 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
if (scheduledStatus != null) outState.putParcelable("scheduledStatus", Parcels.wrap(scheduledStatus));
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ if (requestCode == CAMERA_PERMISSION_CODE && (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST_CODE);
+ } else {
+ Toast.makeText(getContext(), R.string.permission_required, Toast.LENGTH_SHORT);
+ }
+ }
+
@Override
public void onResume(){
super.onResume();
@@ -1427,6 +1459,17 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
}
+
+ if(requestCode==CAMERA_PIC_REQUEST_CODE && resultCode==Activity.RESULT_OK){
+ Bitmap image = (Bitmap) data.getExtras().get("data");
+ String path = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), image, null, null);
+ addMediaAttachment(Uri.parse(path), null);
+ }
+ }
+
+ @Subscribe
+ public void onPictureTaken(PictureTakenEvent ev){
+ addMediaAttachment(ev.uri, null);
}
private boolean addMediaAttachment(Uri uri, String description){
diff --git a/mastodon/src/main/res/drawable/ic_fluent_camera_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_camera_24_regular.xml
new file mode 100644
index 000000000..f48869406
--- /dev/null
+++ b/mastodon/src/main/res/drawable/ic_fluent_camera_24_regular.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/mastodon/src/main/res/menu/attach.xml b/mastodon/src/main/res/menu/attach.xml
index 6e3fa27a0..6e8c92952 100644
--- a/mastodon/src/main/res/menu/attach.xml
+++ b/mastodon/src/main/res/menu/attach.xml
@@ -3,9 +3,14 @@
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values/strings_mo.xml b/mastodon/src/main/res/values/strings_mo.xml
index 45f10ad35..b55cfe836 100644
--- a/mastodon/src/main/res/values/strings_mo.xml
+++ b/mastodon/src/main/res/values/strings_mo.xml
@@ -32,6 +32,7 @@
Reply as \'Unlisted\' by default
Composer\'s Behavior
Manage Notifications
+ Take picture
Add new poll option