I created my own custom view. This multilistpicker selects multiple rows from the list.
When he tries to binding data, it get this error.
"SetValue failed with exception - ArgumentException: Object of type 'System.Collections.Generic.List1[System.Object]' cannot be converted to type 'System.Collections.Generic.List1[isvk.Core.Models.NtdChecked]'"
My control:
<isvk.Controls.MultipleListPicker
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/report_field_margin_top_bottom"
local:lp_label="#string/ReportMTRDataNtd"
local:lp_icon="#drawable/icon_list"
local:lp_targetProperty="Title"
local:MvxBind="Items Ntds; CheckedItems NtdCheckedList, Converter=ListObject; NewItem AddNewNtdItemCommand" />
My converter:
public class ListObjectConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
I created my own Converter, but I can't connect it. In debug mode, the program does not enter the Converter. Where or what do I change below code to work.
My MultipleListPicker:
public class MultipleListPicker : ListPicker
{
private readonly IList<object> _checkedItemsCancelable = new List<object>();
private IEnumerable<object> _checkedItems;
public MultipleListPicker(Context context, IAttributeSet attrs)
: base(context, attrs)
{
_listView.ChoiceMode = ChoiceMode.Multiple;
_dialog = new AlertDialog.Builder(Context).SetView(_pickerListView).SetCancelable(true)
.SetPositiveButton(Resource.String.ReadyText, OnReadyClicked)
.SetNegativeButton(Resource.String.CancelText, (sender, args) => _dialog.Dismiss()).Create();
}
public IEnumerable CheckedItems
{
get { return _checkedItems; }
private set
{
_checkedItems = new List<object>((IEnumerable<object>) value);
SelectionChanged?.Invoke(this, new MultipleSelectionEventArgs(_checkedItems));
}
}
protected override void OnClick(object sender, EventArgs args)
{
_listView.ClearChoices();
_checkedItemsCancelable.Clear();
for (var i = 0; i < _listView.ChildCount; i++)
{
SetDeselectedBackground(i);
}
if (CheckedItems != null)
{
foreach (var obj in CheckedItems)
{
SelectItem(obj);
}
}
base.OnClick(sender, args);
}
protected override void ListViewOnItemSelected(object obj)
{
if (!IsItemSelected(obj))
{
SelectItem(obj);
}
else
{
DeselectItem(obj);
}
}
private void SetSelectedBackground(int index)
{
try
{
var v = _listView.GetChildAt(index);
v.SetBackgroundResource(Resource.Color.colorPrimary);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
private void SelectItem(object obj)
{
var index = _listView.Adapter.GetPosition(obj);
_listView.SetItemChecked(index, true);
_checkedItemsCancelable.Add(obj);
SetSelectedBackground(index);
}
private void SetDeselectedBackground(int index)
{
var v = _listView.GetChildAt(index);
v.SetBackgroundResource(Resource.Color.white);
}
private void DeselectItem(object obj)
{
var index = _listView.Adapter.GetPosition(obj);
_listView.SetItemChecked(index, false);
_checkedItemsCancelable.Remove(obj);
SetDeselectedBackground(index);
}
private bool IsItemSelected(object obj)
{
return _checkedItemsCancelable.Contains(obj);
}
private void OnReadyClicked(object sender, DialogClickEventArgs eventArgs)
{
var hasSelection = false;
var builder = new StringBuilder(string.Empty);
foreach (var checkedItem in _checkedItemsCancelable)
{
hasSelection = true;
builder.Append(checkedItem);
builder.Append("; ");
}
if (hasSelection)
{
_contentTextView.Text = builder.ToString();
}
else
{
_contentTextView.SetText(Resource.String.NotSelectedText);
}
CheckedItems = _checkedItemsCancelable;
}
public event EventHandler<MultipleSelectionEventArgs> SelectionChanged;
}
public class MultipleSelectionEventArgs : EventArgs
{
public MultipleSelectionEventArgs(IEnumerable checkedItems)
{
CheckedItems = checkedItems;
}
public IEnumerable CheckedItems { get; }
}
My project struct:
enter image description here
Related
I am trying connect React Native with Mailcore2. Use mailcore2-android-4.aar (already build): http://d.etpan.org/mailcore2-deps/mailcore2-android/
I create my class and connect it with React Native App, as a result I can use debug in Android Studio 2021.3.1 (Dolphin)
My code:
public class Mail extends ReactContextBaseJavaModule {
private ReactContext mReactContext;
private IMAPFetchMessagesOperation fetchMessagesOp;
private java.util.List\<IMAPMessage\> messages;
private IMAPSession session;
private String status = "Failed";
public interface Callbacks {}
public Mail(ReactApplicationContext reactContext) {
super(reactContext);
this.mReactContext = reactContext;
session = new IMAPSession();
session.setUsername("my-email");
session.setPassword("my-client-secret");
session.setHostname("imap.yandex.ru");
session.setPort(993);
session.setConnectionType(ConnectionType.ConnectionTypeTLS);
}
#Override
public String getName() {
return "Mail";
}
#ReactMethod
public void updateMessages(Callback cb) {
fetchMessagesOp = session.fetchMessagesByNumberOperation(
"INBOX",
IMAPMessagesRequestKind.IMAPMessagesRequestKindHeaders |
IMAPMessagesRequestKind.IMAPMessagesRequestKindStructure,
IndexSet.indexSetWithRange(new Range(1, Range.RangeMax))
);
fetchMessagesOp.start(new OperationCallback() {
#Override
public void succeeded() {
status = "OK";
messages = fetchMessagesOp.messages();
cb.invoke(null, "");
}
#Override
public void failed(MailException ex) {
cb.invoke(ex.toString(), null);
}
});
}
#ReactMethod
public void getStatus(Callback cb) {
try {
if (Objects.equals(status, "OK")) {
cb.invoke(null, "OK");
} else {
cb.invoke("Failed", null);
}
} catch (Exception ex) {
cb.invoke(ex.toString(), null);
}
}
#ReactMethod
public void getMessages(Callback cb) {
if (messages != null) {
String tempString = "";
for (int indexMsg = 0; indexMsg < messages.size(); ++indexMsg) {
tempString += messages.get(indexMsg).toString();
}
cb.invoke(null, tempString);
} else {
cb.invoke("No messages", null);
}
}
}
My code for calling this class from React Native App:
let status = false;
function checkStatus() {
console.log('checkStatus');
NativeModules.Mail.getStatus((err: any, s: string) =\> {
if (err !== null) {
console.log(s);
} else {
status = true;
}
});
if (status === false) setTimeout(checkStatus, 5000);
}
function getMessages() {
NativeModules.Mail.updateMessages((err: any, s: string) =\> {
if (err === null) {
console.log(s);
} else {
console.log(err);
}
});
When I clicked on the button with included getMessages(), App crashed
I have a Xamarin Forms project on visual studio 2019.
I wanted to hide the cancel button from a simple Picker but wasn't able to do so, so I have now a custom picker but don't know how to remove that button. Either that or changing the "Cancel" button for an "Ok" would be what I want.
The thing is the examples that I have seen are customizing this by using the NumberPicker class and this won't work for me as I don't want to display my list that way.
My CustomPicker class
public class CustomPicker : Picker
{
public static readonly BindableProperty ImageProperty =
BindableProperty.Create(nameof(Image), typeof(string), typeof(CustomPicker), string.Empty);
public string Image
{
get { return (string)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
}
My CustomPickerRenderer class on Android project
public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
{
public CustomPickerRenderer(Context context) : base(context) { }
CustomPicker element;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
element = (CustomPicker)this.Element;
if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
Control.Background = AddPickerStyles(element.Image);
Control.Gravity = GravityFlags.CenterHorizontal;
}
}
public LayerDrawable AddPickerStyles(string imagePath)
{
ShapeDrawable border = new ShapeDrawable();
border.Paint.Color = Android.Graphics.Color.Gray;
border.SetPadding(10, 10, 10, 10);
border.Paint.SetStyle(Paint.Style.Stroke);
Drawable[] layers = { border, GetDrawable(imagePath) };
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.SetLayerInset(0, 0, 0, 0, 0);
return layerDrawable;
}
private BitmapDrawable GetDrawable(string imagePath)
{
int resID = Resources.GetIdentifier(imagePath, "drawable", this.Context.PackageName);
var drawable = ContextCompat.GetDrawable(this.Context, resID);
var bitmap = ((BitmapDrawable)drawable).Bitmap;
var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 70, 70, true));
result.Gravity = Android.Views.GravityFlags.Right;
return result;
}
}
My CustomPickerRenderer on iOS project
public class CustomPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
var element = (CustomPicker)this.Element;
if (this.Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
var downarrow = UIImage.FromBundle(element.Image);
Control.RightViewMode = UITextFieldViewMode.Always;
Control.RightView = new UIImageView(downarrow);
Control.TextAlignment = UITextAlignment.Center;
}
}
}
How can I achieve this? Please help and thanks.
You can set a donetextproperty in your picker and set it in the uibuttontext on ios side.like:
public class MyPicker:Picker
{
public static readonly BindableProperty DonebuttonTextProperty = BindableProperty.Create("DonebuttonText", typeof(string),
typeof(string), null);
public string DonebuttonText { get { return (string)GetValue(DonebuttonTextProperty); }
set { SetValue(DonebuttonTextProperty, value); }
}
public MyPicker()
{
}
}
}
iOSRenderer:
public class MyPickerRenderer:PickerRenderer
{
public MyPickerRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null) return;
var customPicker = e.NewElement as MyPicker;
if (Control == null)
{
SetNativeControl(new UITextField
{
RightViewMode = UITextFieldViewMode.Always,
ClearButtonMode = UITextFieldViewMode.WhileEditing
});
SetUIbutton(customPicker.DonebuttonText);
}
else
{ SetUIbutton(customPicker.DonebuttonText); }
}
public void SetUIbutton(string doneButtonText)
{
UIToolbar toolbar = new UIToolbar();
toolbar.BarStyle = UIBarStyle.Default;
toolbar.Translucent = true;
toolbar.SizeToFit();
UIBarButtonItem doneButton = new UIBarButtonItem(string.IsNullOrEmpty(doneButtonText) ? "OK" : doneButtonText,
UIBarButtonItemStyle.Done, (s, ev) => { Control.ResignFirstResponder(); });
UIBarButtonItem flexible = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
toolbar.SetItems(new UIBarButtonItem[] { doneButton, flexible }, true);
Control.InputAccessoryView = toolbar;
}
}
As for android, change text in NegativeButton like:
public class MyPickerRenderer : PickerRenderer
{
public MyPickerRenderer(Context context) : base(context)
{
}
private IElementController ElementController => Element as IElementController;
private AlertDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.NewElement == null || e.OldElement != null)
return;
Control.Click += Control_Click;
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click;
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetNegativeButton("OK ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Done", (s, a) =>
{
ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
}
I am working on a media player app. I'm using ExoPlayer library. I have a playlist of videos, and I want to download videos simultaneously. I done it by using available demo app of exoplayer library on GitHub. I want to show progress of each downloading in the UI. For this job I get help from DownloadNotificationUtil.buildProgressNotification method.
#Override
protected Notification getForegroundNotification(TaskState[] taskStates) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadTasks = false;
boolean haveRemoveTasks = false;
Log.e(TAG,"size task state: "+taskStates.length);
for (TaskState taskState : taskStates) {
Log.e(TAG,"taskId= "+taskState.taskId);
if (taskState.state != TaskState.STATE_STARTED
&& taskState.state != TaskState.STATE_COMPLETED) {
continue;
}
if (taskState.action.isRemoveAction) {
haveRemoveTasks = true;
continue;
}
haveDownloadTasks = true;
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += taskState.downloadPercentage;
}
haveDownloadedBytes |= taskState.downloadedBytes > 0;
downloadTaskCount++;
}
int progress = 0;
boolean indeterminate = true;
if (haveDownloadTasks) {
progress = (int) (totalPercentage / downloadTaskCount);
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
Log.e(TAG,"notifi "+progress);
}
return DownloadNotificationUtil.buildProgressNotification(
this,
R.drawable.exo_icon_play,
DOWNLOAD_CHANNEL_ID,
null,
null,
taskStates);
}
Now,I can track the progress downloading. But I still have a problem. I can't understand which item is downloading to update it's progress bar in the UI. Is there a Identical id of each download to recognize it? For example Android Download Manager has a download ID for each downloading file. But I don't know , how to handle this problem.
This is MediaDownloadService:
public class MediaDownloadService extends DownloadService {
public static String TAG="MediaDownloadService";
private static final int FOREGROUND_NOTIFICATION_ID = 1;
public MediaDownloadService() {
super(
DOWNLOAD_NOTIFICATION_ID,
DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL,
DOWNLOAD_CHANNEL_ID,
R.string.download_channel_name);
}
#Override
protected DownloadManager getDownloadManager() {
return ((MyApplication) getApplication()).getDownloadManager();
}
#Nullable
#Override
protected Scheduler getScheduler() {
return null;
}
#Override
protected Notification getForegroundNotification(TaskState[] taskStates) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadTasks = false;
boolean haveRemoveTasks = false;
for (TaskState taskState : taskStates) {
if (taskState.state != TaskState.STATE_STARTED
&& taskState.state != TaskState.STATE_COMPLETED) {
continue;
}
if (taskState.action.isRemoveAction) {
haveRemoveTasks = true;
continue;
}
haveDownloadTasks = true;
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += taskState.downloadPercentage;
}
haveDownloadedBytes |= taskState.downloadedBytes > 0;
downloadTaskCount++;
}
int progress = 0;
boolean indeterminate = true;
if (haveDownloadTasks) {
progress = (int) (totalPercentage / downloadTaskCount);
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
Log.e(TAG,"notifi "+progress);
sendIntent(progress);
}
return DownloadNotificationUtil.buildProgressNotification(
this,
R.drawable.exo_icon_play,
DOWNLOAD_CHANNEL_ID,
null,
null,
taskStates);
}
private void sendIntent(int progress){
Intent intent = new Intent(ConstantUtil.MESSAGE_PROGRESS);
intent.putExtra("progress",progress);
LocalBroadcastManager.getInstance(MediaDownloadService.this).sendBroadcast(intent);
}
#Override
protected void onTaskStateChanged(TaskState taskState) {
if (taskState.action.isRemoveAction) {
return;
}
Notification notification = null;
if (taskState.state == TaskState.STATE_COMPLETED) {
Log.e(TAG,"STATE_COMPLETED");
notification =
DownloadNotificationUtil.buildDownloadCompletedNotification(
/* context= */ this,
R.drawable.exo_controls_play,
DOWNLOAD_CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
} else if (taskState.state == TaskState.STATE_FAILED) {
Log.e(TAG,"STATE_FAILED");
notification =
DownloadNotificationUtil.buildDownloadFailedNotification(
/* context= */ this,
R.drawable.exo_controls_play,
DOWNLOAD_CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
}
int notificationId = FOREGROUND_NOTIFICATION_ID + 1 + taskState.taskId;
NotificationUtil.setNotification(this, notificationId, notification);
}
}
This is DownloadTracker class:
public class DownloadTracker implements DownloadManager.Listener {
/** Listens for changes in the tracked downloads. */
public interface Listener {
/** Called when the tracked downloads changed. */
void onDownloadsChanged();
}
private static final String TAG = "DownloadTracker";
private final Context context;
private final DataSource.Factory dataSourceFactory;
private final TrackNameProvider trackNameProvider;
private final CopyOnWriteArraySet<Listener> listeners;
private Listener onDownloadsChanged;
private final HashMap<Uri, DownloadAction> trackedDownloadStates;
private final ActionFile actionFile;
private final Handler actionFileWriteHandler;
public DownloadTracker(
Context context,
DataSource.Factory dataSourceFactory,
File actionFile,
DownloadAction.Deserializer... deserializers) {
this.context = context.getApplicationContext();
this.dataSourceFactory = dataSourceFactory;
this.actionFile = new ActionFile(actionFile);
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
listeners = new CopyOnWriteArraySet<>();
trackedDownloadStates = new HashMap<>();
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
actionFileWriteThread.start();
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
loadTrackedActions(
deserializers.length > 0 ? deserializers : DownloadAction.getDefaultDeserializers());
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
public boolean isDownloaded(Uri uri) {
return trackedDownloadStates.containsKey(uri);
}
#SuppressWarnings("unchecked")
public List<StreamKey> getOfflineStreamKeys(Uri uri) {
if (!trackedDownloadStates.containsKey(uri)) {
return Collections.emptyList();
}
return trackedDownloadStates.get(uri).getKeys();
}
public int toggleDownload(Activity activity, String name, Uri uri, String extension) {
if (isDownloaded(uri)) {
Log.e(TAG,"isDownloaded");
DownloadAction removeAction =
getDownloadHelper(uri, extension).getRemoveAction(Util.getUtf8Bytes(name));
startServiceWithAction(removeAction);
return -1;
} else {
StartDownloadDialogHelper helper =
new StartDownloadDialogHelper(activity, getDownloadHelper(uri, extension), name);
helper.prepare();
return helper.getTaskId();
}
}
#Override
public void onInitialized(DownloadManager downloadManager) {
// Do nothing.
}
#Override
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
DownloadAction action = taskState.action;
Uri uri = action.uri;
if ((action.isRemoveAction && taskState.state == TaskState.STATE_COMPLETED)
|| (!action.isRemoveAction && taskState.state == TaskState.STATE_FAILED)) {
// A download has been removed, or has failed. Stop tracking it.
if (trackedDownloadStates.remove(uri) != null) {
handleTrackedDownloadStatesChanged();
}
}
}
#Override
public void onIdle(DownloadManager downloadManager) {
// Do nothing.
}
// Internal methods
private void loadTrackedActions(DownloadAction.Deserializer[] deserializers) {
try {
DownloadAction[] allActions = actionFile.load(deserializers);
for (DownloadAction action : allActions) {
trackedDownloadStates.put(action.uri, action);
}
} catch (IOException e) {
Log.e(TAG, "Failed to load tracked actions", e);
}
}
private void handleTrackedDownloadStatesChanged() {
for (Listener listener : listeners) {
listener.onDownloadsChanged();
}
final DownloadAction[] actions = trackedDownloadStates.values().toArray(new DownloadAction[0]);
Log.e(TAG,"actions: "+actions.toString());
actionFileWriteHandler.post(
() -> {
try {
actionFile.store(actions);
} catch (IOException e) {
Log.e(TAG, "Failed to store tracked actions", e);
}
});
}
private void startDownload(DownloadAction action) {
if (trackedDownloadStates.containsKey(action.uri)) {
// This content is already being downloaded. Do nothing.
Log.e(TAG,"download already exsit");
return;
}
trackedDownloadStates.put(action.uri, action);
handleTrackedDownloadStatesChanged();
startServiceWithAction(action);
}
private void startServiceWithAction(DownloadAction action) {
DownloadService.startWithAction(context, MediaDownloadService.class, action, false);
}
private DownloadHelper getDownloadHelper(Uri uri, String extension) {
int type = Util.inferContentType(uri, extension);
switch (type) {
case C.TYPE_DASH:
return new DashDownloadHelper(uri, dataSourceFactory);
case C.TYPE_SS:
return new SsDownloadHelper(uri, dataSourceFactory);
case C.TYPE_HLS:
return new HlsDownloadHelper(uri, dataSourceFactory);
case C.TYPE_OTHER:
return new ProgressiveDownloadHelper(uri);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
}
private final class StartDownloadDialogHelper
implements DownloadHelper.Callback, DialogInterface.OnClickListener {
private final DownloadHelper downloadHelper;
private final String name;
private final AlertDialog.Builder builder;
private final View dialogView;
private final List<TrackKey> trackKeys;
private final ArrayAdapter<String> trackTitles;
private final ListView representationList;
private int taskId;
public StartDownloadDialogHelper(
Activity activity, DownloadHelper downloadHelper, String name) {
this.downloadHelper = downloadHelper;
this.name = name;
builder =
new AlertDialog.Builder(activity)
.setTitle(R.string.exo_download_description)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null);
// Inflate with the builder's context to ensure the correct style is used.
LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
dialogView = dialogInflater.inflate(R.layout.start_download_dialog, null);
trackKeys = new ArrayList<>();
trackTitles =
new ArrayAdapter<>(
builder.getContext(), android.R.layout.simple_list_item_multiple_choice);
representationList = dialogView.findViewById(R.id.representation_list);
representationList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
representationList.setAdapter(trackTitles);
}
public void prepare() {
downloadHelper.prepare(this);
}
#Override
public void onPrepared(DownloadHelper helper) {
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
TrackGroupArray trackGroups = downloadHelper.getTrackGroups(i);
for (int j = 0; j < trackGroups.length; j++) {
TrackGroup trackGroup = trackGroups.get(j);
for (int k = 0; k < trackGroup.length; k++) {
trackKeys.add(new TrackKey(i, j, k));
trackTitles.add(trackNameProvider.getTrackName(trackGroup.getFormat(k)));
}
}
}
if (!trackKeys.isEmpty()) {
builder.setView(dialogView);
}
builder.create().show();
}
#Override
public void onPrepareError(DownloadHelper helper, IOException e) {
Toast.makeText(
context.getApplicationContext(), R.string.download_start_error, Toast.LENGTH_LONG)
.show();
Log.e(TAG, "Failed to start download", e);
}
#Override
public void onClick(DialogInterface dialog, int which) {
ArrayList<TrackKey> selectedTrackKeys = new ArrayList<>();
for (int i = 0; i < representationList.getChildCount(); i++) {
if (representationList.isItemChecked(i)) {
selectedTrackKeys.add(trackKeys.get(i));
}
}
if (!selectedTrackKeys.isEmpty() || trackKeys.isEmpty()) {
// We have selected keys, or we're dealing with single stream content.
DownloadAction downloadAction =
downloadHelper.getDownloadAction(Util.getUtf8Bytes(name), selectedTrackKeys);
taskId=MyApplication.getInstance().getDownloadManager().handleAction(downloadAction);
startDownload(downloadAction);
}
}
}
}
In my Fragment/Activity:
/* this method will be called when user click on download button of each item */
#Override
public void onDownloadClick(LectureList lecture) {
Log.e(TAG,"onClickDownload");
downloadTracker.toggleDownload(this,lecture.getTitle_lecture(),
Uri.parse(lecture.getUrlPath()),lecture.getExtension());
}
And here is my broadcast receiver:
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG,"onRecive download");
if(intent.getAction().equals(MESSAGE_PROGRESS)){
int progress=intent.getLongExtra("progress",0);
}
}
};
In the getForegroundNotification() method, you will get list of TaskState objects, which has a members downloadPercentage and your download Uri taskState.action.uri which is unique for each download task. Store these variables into a map and broadcast the map.
override fun getForegroundNotification(taskStates: Array<TaskState>): Notification {
var totalPercentage = 0f
var downloadTaskCount = 0
var progressMap : HashMap<Uri, Int> = HashMap()
for (taskState in taskStates) {
if (taskState.state != TaskState.STATE_STARTED && taskState.state != TaskState.STATE_COMPLETED) {
continue
}
if (taskState.action.isRemoveAction) {
continue
}
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET.toFloat()) {
totalPercentage += taskState.downloadPercentage
progressMap.put(taskState.action.uri, taskState.downloadPercentage.toInt())
}
downloadTaskCount++
}
var progress = 0
progress = (totalPercentage / downloadTaskCount).toInt()
broadcastIndividualProgress(progressMap)
return buildProgressNotification(progress)
}
This is my api
{}JSON
[]products
{}0
product-name : "Fiting"
product-id : "1"
product-description : "Door"
product-image : "https://image/logo.jpg"
product-categoryid : "2"
category-name : "Furniture"
{}1
product-name : "Bathroom"
product-id : "2"
product-description : "Services"
product-image : "https://image/logo.jpg"
product-categoryid : "1"
category-name : "Plumber"
subcategory-id : "1"
subcategory-name : "Bathroom"
subCategoryDetailModelClass.setSubCategoryId(productObject.getInt("subcategory-id"));
subCategoryDetailModelClass.setSubCategoryName(productObject.getString("subcategory-name"));
i cannot add subcategory-id,subcategory-name in my arraylist since it is not available at 0th position.....so how to check condition that if in api subcategory-id,subcategory-name is not available add other items in the list
StringRequest stringRequest = new StringRequest(Request.Method.GET,URLs.productURL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("zsded", response.toString());
try {
JSONObject obj = new JSONObject(response);
JSONArray productArray = obj.getJSONArray("products");
//now looping through all the elements of the json array
for (int i = 0; i < productArray.length(); i++) {
JSONObject productObject = productArray.getJSONObject(i);
SubCategoryDetailModelClass subCategoryDetailModelClass = new SubCategoryDetailModelClass();
// if(productObject.getInt("subcategory-id"))
subCategoryDetailModelClass.setProduct_name(productObject.getString("product-name"));
subCategoryDetailModelClass.setProduct_id(productObject.getInt("product-id"));
subCategoryDetailModelClass.setProduct_desc(productObject.getString("product-description"));
subCategoryDetailModelClass.setProduct_imgURL(productObject.getString("product-image"));
subCategoryDetailModelClass.setProduct_CategoryId(productObject.getInt("product-categoryid"));
subCategoryDetailModelClass.setProduct_Category_Name(productObject.getString("category-name"));
subCategoryDetailModelClass.setSubCategoryId(productObject.getInt("subcategory-id"));
subCategoryDetailModelClass.setSubCategoryName(productObject.getString("subcategory-name"));
subCategoryListDetailModelClassArray.add(subCategoryDetailModelClass);
Log.d("subcatdetail", String.valueOf(subCategoryDetailModelClass));
}
Use this class
public class JSONHelper {
public static String getString(JSONObject json, String tag) throws JSONException {
if(mJSONValueAvailable(json, tag)) {
return json.getString(tag);
}
return "";
}
public static int getInt(JSONObject json, String tag) throws JSONException {
if(mJSONValueAvailable(json, tag)) {
if(json.get(tag) instanceof String) {
if(json.getString(tag).equalsIgnoreCase("None")) {
return -1;
}
if(!json.getString(tag).equals("")) {
return Integer.parseInt(json.getString(tag));
} else {
return -1;
}
}
return json.getInt(tag);
}
return -1;
}
public static boolean getBoolean(JSONObject json, String tag) throws JSONException {
if(mJSONValueAvailable(json, tag)) {
Object value = json.get(tag);
if(value instanceof String) {
return PrimitiveHelper.StringToBoolean((String) value);
} else if (value instanceof Integer) {
return PrimitiveHelper.IntegerToBoolean((int)value);
}
return json.getBoolean(tag);
}
return false;
}
public static Boolean getBooleanBoxed(JSONObject json, String tag) throws JSONException {
if(mJSONValueAvailable(json, tag)) {
Object value = json.get(tag);
if(value instanceof String) {
return PrimitiveHelper.StringToBooleanBoxed((String) value);
} else if (value instanceof Integer) {
return PrimitiveHelper.IntegerToBooleanBoxed((int) value);
}
return json.getBoolean(tag);
}
return null;//false;
}
private static boolean mJSONValueAvailable(JSONObject json, String tag) {
return json.has(tag) && !json.isNull(tag);
}
// private static Boolean mJSONValueAvailableBoxed(JSONObject json, String tag) {
// return json.has(tag) && !json.isNull(tag);//
// }
public static JSONArray sortJsonArray(JSONArray array, String sort) {
final String sortKey = sort;
//Logger.d("sortJSONArray by::: " + sortKey);
List<JSONObject> jsons = new ArrayList<JSONObject>();
try {
for (int i = 0; i < array.length(); i++) {
jsons.add(array.getJSONObject(i));
}
Collections.sort(jsons, new Comparator<JSONObject>() {
#Override
public int compare(JSONObject lhs, JSONObject rhs) {
try {
String lid = lhs.getString(sortKey);
String rid = rhs.getString(sortKey);
// Here you could parse string id to integer and then compare.
return lid.compareTo(rid);
} catch (JSONException e) {
e.printStackTrace();
}
return 0;
}
});
} catch (JSONException e) {
e.printStackTrace();
}
return new JSONArray(jsons);
}
}
Call this as follows
subCategoryDetailModelClass.setProduct_name(JSONHelper.getString(productObject, "product-name"));
subCategoryDetailModelClass.setProduct_id(JSONHelper.getInt(productObject,"product-id"));
subCategoryDetailModelClass.setProduct_desc(JSONHelper.getString(productObject, "product-description"));
subCategoryDetailModelClass.setProduct_imgURL(JSONHelper.getString(productObject, "product-image"));
subCategoryDetailModelClass.setProduct_CategoryId(JSONHelper.getInt(productObject,"product-categoryid"));
subCategoryDetailModelClass.setProduct_Category_Name(JSONHelper.getString(productObject, "category-name"));
subCategoryDetailModelClass.setSubCategoryId(JSONHelper.getInt(productObject, "subcategory-id"));
subCategoryDetailModelClass.setSubCategoryName(JSONHelper.getString(productObject,"subcategory-name"));
subCategoryListDetailModelClassArray.add(subCategoryDetailModelClass);
Use Opt methods, For e.g.
optInt(String name, int fallback)
Returns the value mapped by name if it exists and is an int or can be
coerced to an int, or fallback otherwise.
There are optMethods for mostly primitive datatypes, check here
I am developing a messaging application for Android and I am using an Azure Web API as my backend which connects to an Azure SQL DB. I am trying to get the service to allow users to log in and proceed through the application with an identity. I want to use Individual User Accounts to do this but I do not know how.
I have been through every piece of documentation on the internet and yet I am still at a loss on how to receive a token from the service and use it to access auhtorised resources.
If someone could please highlight the appropriate methods I need to call from the generated classes as well as methods I should write myself, that would be very helpful!
This is the Account Controller that was generated:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using AcademicAssistant.Models;
using AcademicAssistant.Providers;
using AcademicAssistant.Results;
namespace AcademicAssistant.Controllers
{
[Authorize]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
[Route("ManageInfo")]
public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
{
IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user == null)
{
return null;
}
List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
foreach (IdentityUserLogin linkedAccount in user.Logins)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = linkedAccount.LoginProvider,
ProviderKey = linkedAccount.ProviderKey
});
}
if (user.PasswordHash != null)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = LocalLoginProvider,
ProviderKey = user.UserName,
});
}
return new ManageInfoViewModel
{
LocalLoginProvider = LocalLoginProvider,
Email = user.UserName,
Logins = logins,
ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
};
}
// POST api/Account/ChangePassword
[Route("ChangePassword")]
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/SetPassword
[Route("SetPassword")]
public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/AddExternalLogin
[Route("AddExternalLogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/RemoveLogin
[Route("RemoveLogin")]
public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
if (model.LoginProvider == LocalLoginProvider)
{
result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
}
else
{
result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(model.LoginProvider, model.ProviderKey));
}
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("ExternalLogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST api/Account/Register
[AllowAnonymous]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
base.Dispose(disposing);
}
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
private class ExternalLoginData
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string UserName { get; set; }
public IList<Claim> GetClaims()
{
IList<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));
if (UserName != null)
{
claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
}
return claims;
}
public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
|| String.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
{
return null;
}
return new ExternalLoginData
{
LoginProvider = providerKeyClaim.Issuer,
ProviderKey = providerKeyClaim.Value,
UserName = identity.FindFirstValue(ClaimTypes.Name)
};
}
}
private static class RandomOAuthStateGenerator
{
private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();
public static string Generate(int strengthInBits)
{
const int bitsPerByte = 8;
if (strengthInBits % bitsPerByte != 0)
{
throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
}
int strengthInBytes = strengthInBits / bitsPerByte;
byte[] data = new byte[strengthInBytes];
_random.GetBytes(data);
return HttpServerUtility.UrlTokenEncode(data);
}
}
#endregion
}
}
This is the message controller I wrote:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using AcademicAssistant.Models;
namespace AcademicAssistant.Controllers
{
[Authorize]
public class MessagesController : ApiController
{
private AcademicAssistantContext db = new AcademicAssistantContext();
// GET: api/Messages
[Authorize]
public IQueryable<Message> GetMessages()
{
return db.Messages;
}
// GET: api/Messages/5
[Authorize]
[ResponseType(typeof(Message))]
public async Task<IHttpActionResult> GetMessage(int id)
{
Message message = await db.Messages.FindAsync(id);
if (message == null)
{
return NotFound();
}
return Ok(message);
}
// PUT: api/Messages/5
[Authorize]
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutMessage(int id, Message message)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != message.MessageID)
{
return BadRequest();
}
db.Entry(message).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MessageExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Messages
[Authorize]
[ResponseType(typeof(Message))]
public async Task<IHttpActionResult> PostMessage(Message message)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Messages.Add(message);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = message.MessageID }, message);
}
// DELETE: api/Messages/5
[Authorize]
[ResponseType(typeof(Message))]
public async Task<IHttpActionResult> DeleteMessage(int id)
{
Message message = await db.Messages.FindAsync(id);
if (message == null)
{
return NotFound();
}
db.Messages.Remove(message);
await db.SaveChangesAsync();
return Ok(message);
}
[Authorize]
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
[Authorize]
private bool MessageExists(int id)
{
return db.Messages.Count(e => e.MessageID == id) > 0;
}
}
}