Xamarin Android image url array into gridview - c#

I just want to change my resource.drawable.image into URL, but I don't know how I can do that. I try using bitmap method but I don't know how I can make it array using this method. The purpose of this is I want to get the data from the database and store it into my List<> or array so the output will be like this picture. It's working fine in resource.drawable.image but I want to change into into url value.
By the way, I already stored the column ID from the database. I also try to store the image_link column from the database into my while loop and call it into my List<> but I get error. See my code at below --> Fragment1.cs
All of these codes are working.
fragment_layout.axml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:padding="16dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<GridView
android:id="#+id/grid_view_image_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="110dp"
android:gravity="center"
android:numColumns="auto_fit"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center" />
</FrameLayout>
gridview_layout.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="15dp"
android:id="#+id/imageViewGrid"/>
<TextView
android:layout_marginTop="5dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/textViewGrid"/>
</LinearLayout>
CustomGridViewAdapter.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
namespace testing_code
{
public class CustomGridViewAdapter : BaseAdapter
{
private Context context;
private string[] gridViewString;
private int[] gridViewImage;
public CustomGridViewAdapter(Context context, string[] gridViewstr, int[] gridViewImage)
{
this.context = context;
gridViewString = gridViewstr;
this.gridViewImage = gridViewImage;
}
public override int Count
{
get
{
return gridViewString.Length;
}
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view;
LayoutInflater inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
if(convertView == null)
{
view = new View(context);
view = inflater.Inflate(Resource.Layout.gridview_layout, null);
TextView txtview = view.FindViewById<TextView>(Resource.Id.textViewGrid);
ImageView imgview = view.FindViewById<ImageView>(Resource.Id.imageViewGrid);
txtview.Text = gridViewString[position];
imgview.SetImageResource(gridViewImage[position]);
}
else
{
view = (View)convertView;
}
return view;
}
//private Bitmap GetImageBitmapFromUrl(string url)
//{
// Bitmap imageBitmap = null;
// using (var webClient = new WebClient())
// {
// var imageBytes = webClient.DownloadData(url);
// if (imageBytes != null && imageBytes.Length > 0)
// {
// imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
// }
// }
// return imageBitmap;
//}
}
}
Fragment1.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using SupportFragment = Android.Support.V4.App.Fragment;
using Android.Support.Design.Widget;
using Android.Support.V7.App;
using Android.Support.V4.Widget;
using Android.Support.V4.App;
using MySql.Data.MySqlClient;
using System.Data;
namespace testing_code
{
public class Fragment1 : SupportFragment
{
MySqlConnection conn = new MySqlConnection();
string query = "server=localhost;port=3306;database=dbsample;user id=root;password=123";
GridView gridview;
//string[] gridviewstring = {
// "location", "sound", "note"
//};
//int[] imgview =
//{
// Resource.Drawable.ic_dashboard, Resource.Drawable.ic_headset, Resource.Drawable.ic_dashboard
//};
List<string> gridviewstring = new List<string>();
List<int> imgview = new List<int>();
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
View view = inflater.Inflate(Resource.Layout.fragment_layout, container, false);
conn.ConnectionString = query;
//
MySqlCommand cmd = new MySqlCommand("Select * from wp_kdskli23jkposts where ID in (1,2,4)", conn);
try
{
conn.Open();
MySqlDataReader reader = cmd.ExecuteReader();
//Read, get and loop the data value from the database
while (reader.Read())
{
string asd = reader["ID"].ToString();
gridviewstring.Add(asd);
}
}
catch(MySqlException ex)
{
Android.Support.V7.App.AlertDialog.Builder except = new Android.Support.V7.App.AlertDialog.Builder(Activity);
except.SetTitle("Please report this to our website(error server timeout)");
except.SetMessage(ex.ToString());
except.SetPositiveButton("Ok", (senderAlert, args) =>
{
except.Dispose();
});
except.Show();
}
finally
{
conn.Close();
}
//gridviewstring.Add("location");
//gridviewstring.Add("music");
//gridviewstring.Add("book");
imgview.Add(Resource.Drawable.ic_dashboard);
imgview.Add(Resource.Drawable.ic_headset);
imgview.Add(Resource.Drawable.ic_dashboard);
string[] GridViewStringArray = gridviewstring.ToArray();
int[] GridImgViewArray = imgview.ToArray();
CustomGridViewAdapter adapter = new CustomGridViewAdapter(Activity, GridViewStringArray, GridImgViewArray);
gridview = view.FindViewById<GridView>(Resource.Id.grid_view_image_text);
gridview.Adapter = adapter;
return view;
}
}
}

I edited your adapter code to use a list of strings
namespace testing_code
{
public class CustomGridViewAdapter : BaseAdapter
{
private Context context;
private List<string> gridViewString;
private List<string> gridViewImage;
public CustomGridViewAdapter(Context context, List<string> gridViewstr, List<string> gridViewImage)
{
this.context = context;
gridViewString = gridViewstr;
this.gridViewImage = gridViewImage;
}
public override int Count
{
get
{
return gridViewString.Count;
}
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view;
LayoutInflater inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
if (convertView == null)
{
view = new View(context);
view = inflater.Inflate(Resource.Layout.gridview_layout, null);
TextView txtview = view.FindViewById<TextView>(Resource.Id.textViewGrid);
ImageView imgview = view.FindViewById<ImageView>(Resource.Id.imageViewGrid);
txtview.Text = gridViewString[position];
imgview.SetImageBitmap(GetImageBitmapFromUrl(gridViewImage[position]));
}
else
{
view = (View)convertView;
}
return view;
}
private Android.Graphics.Bitmap GetImageBitmapFromUrl(string url)
{
Android.Graphics.Bitmap imageBitmap = null;
using (var webClient = new System.Net.WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
imageBitmap = Android.Graphics.BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
}
}
return imageBitmap;
}
}
}
Then your fragment to use list of URL strings
public class Fragment1 : SupportFragment
{
MySqlConnection conn = new MySqlConnection();
string query = "server=localhost;port=3306;database=dbsample;user id=root;password=123";
GridView gridview;
List<string> gridviewstring = new List<string>();
List<string> imgview = new List<string>();
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate(Resource.Layout.fragment_layout, container, false);
conn.ConnectionString = query;
//
MySqlCommand cmd = new MySqlCommand("Select * from wp_kdskli23jkposts where ID in (1,2,4)", conn);
try
{
conn.Open();
MySqlDataReader reader = cmd.ExecuteReader();
//Read, get and loop the data value from the database
while (reader.Read())
{
string asd = reader["ID"].ToString();
gridviewstring.Add(asd);
}
}
catch (MySqlException ex)
{
Android.Support.V7.App.AlertDialog.Builder except = new Android.Support.V7.App.AlertDialog.Builder(Activity);
except.SetTitle("Please report this to our website(error server timeout)");
except.SetMessage(ex.ToString());
except.SetPositiveButton("Ok", (senderAlert, args) =>
{
except.Dispose();
});
except.Show();
}
finally
{
conn.Close();
}
imgview.Add(" https://www.bellanaija.com/wp-content/uploads/2013/11/Remy-Martins-Pacesetters-VIP-Party-BellaNaija-November2013023-600x398.jpg");
imgview.Add("http://www.allevents.ng/media/2018/at-the-club-with-remy-martins.png?width=375&mode=crop");
imgview.Add("https://i.ytimg.com/vi/iLZz9Becq98/maxresdefault.jpg");
CustomGridViewAdapter adapter = new CustomGridViewAdapter(Activity, gridviewstring, imgview);
gridview = view.FindViewById<GridView>(Resource.Id.grid_view_image_text);
gridview.Adapter = adapter;
return view;
}
}
}
Hope this helps

Related

MAUI-Android: How to keep Google Speech Recognizer from timeout

I am trying out Microsoft .NET MAUI that currently in Preview stage.
I try to make a small Android app that will use Google voice recognizer service as a way to let user navigate the app. Just a small demo to see what can I do with it. This is also my first time to actually write a Xamarin/MAUI project, so I am not really sure what I can actually do wit the platform.
The problem is that I would like to have this Google service to always on (without timeout) or auto-close then re-open when timeout. In short, I want user to never actually have to deal with this screen:
My intention is that the will be a background thread to keep asking user to say the command, only stop when user do, and the service will always ready to receive the speech.
However, I am unable to keep the above service always on or auto-close=>reopen when timeout.
I am search around and it seems that I cannot change the timeout of the service, so the only way is trying to auto-close=>reopen the service, but I don't know how to.
The below is my code, could you guy give me some direction with it?
1. The login page: only have username and password field, use will be asked to say the username. If it is exist, then asked to say password.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiDemo.LoginPage"
BackgroundColor="White">
<ContentPage.Content>
<StackLayout Margin="30" VerticalOptions="StartAndExpand">
<Label
x:Name="lblTitle"
HorizontalTextAlignment="Center"
FontSize="Large"
FontAttributes="Bold"
/>
<Label/>
<Button
x:Name="btnSpeak"
Text="Start"
Clicked="btnSpeak_Clicked"
FontAttributes="Bold"
BackgroundColor="DarkGreen"
/>
<Label/>
<Label
x:Name="lblUsername"
Text="Username"
FontAttributes="Bold"
/>
<Entry
x:Name="txtUsername"
TextColor="Black"
FontSize="18"
VerticalOptions="StartAndExpand"
HorizontalOptions="Fill"
IsReadOnly="True"
/>
<Label/>
<Label
x:Name="lblPassword"
Text="Password"
FontAttributes="Bold"
/>
<Entry
x:Name="txtPassword"
IsPassword="True"
TextColor="Black"
FontSize="18"
VerticalOptions="StartAndExpand"
HorizontalOptions="Fill"
IsReadOnly="True"
/>
<Label/>
<Label
x:Name="lblDisplayname"
Text="Name"
FontAttributes="Bold"
/>
<Label
x:Name="txtDisplayname"
/>
<Label/>
<Label
x:Name="lblMessage"
Text=""/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo
{
public partial class LoginPage : ContentPage
{
private string _field = string.Empty;
private int _waitTime = 2000;
public List<Language> Languages { get; }
private SpeechToTextImplementation _speechRecongnitionInstance;
private struct VoiceMode
{
int Username = 1;
int Password = 2;
}
public LoginPage()
{
InitializeComponent();
this.lblTitle.Text = "Login" + App.Status;
CheckMicrophone();
CommonData.CurrentField = string.Empty;
try
{
_speechRecongnitionInstance = new SpeechToTextImplementation();
_speechRecongnitionInstance.Language = DefaultData.SettingLanguage;
}
catch (Exception ex)
{
DisplayAlert("Error", ex.Message, "OK");
}
MessagingCenter.Subscribe<ISpeechToText, string>(this, "STT", (sender, args) =>
{
ReceivedUsernameAsync(args);
});
MessagingCenter.Subscribe<ISpeechToText>(this, "Final", (sender) =>
{
btnSpeak.IsEnabled = true;
});
MessagingCenter.Subscribe<IMessageSender, string>(this, "STT", (sender, args) =>
{
SpeechToTextRecievedAsync(args);
});
isReceiveUsername = false;
isReceivePassword = false;
RequestUsername();
}
protected override void OnDisappearing()
{
CommonData.CurrentField = string.Empty;
base.OnDisappearing();
}
private async void btnSpeak_Clicked(Object sender, EventArgs e)
{
isReceiveUsername = false;
isReceivePassword = false;
await RequestUsername();
}
private async void SpeechToTextRecievedAsync(string args)
{
switch (_field)
{
case "Username":
await this.ReceivedUsernameAsync(args);
break;
case "Password":
await this.ReceivedPasswordAsync(args);
break;
}
}
bool isReceiveUsername = false;
bool isReceivePassword = false;
private async Task ReceivedUsernameAsync(string args)
{
txtUsername.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtUsername.Text))
{
isReceiveUsername = false;
}
else
{
isReceiveUsername = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()));
if (checkUser.Any())
{
await RequestPassword();
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongUsername);
lblMessage.Text = message;
isReceiveUsername = false;
await RequestUsername(message);
}
}
}
private async Task ReceivedPasswordAsync(string args)
{
txtPassword.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtPassword.Text))
{
isReceivePassword = false;
}
else
{
isReceivePassword = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()) && x.Password.Equals(txtPassword.Text));
if (checkUser.Any())
{
_field = "";
lblDisplayname.Text = checkUser.FirstOrDefault().Displayname;
string msg = CommonData.GetMessage(MessageCode.LoginSuccess);
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
msg
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
await Navigation.PushAsync(new MainPage());
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongPassword);
lblMessage.Text = message;
isReceivePassword = false;
await RequestPassword(message);
}
}
}
private async Task RepeatVoiceUsername(string message)
{
do
{
//_speechRecongnitionInstance.StopSpeechToText();
//_speechRecongnitionInstance.StartSpeechToText();
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceiveUsername);
}
private async Task RepeatVoicePassword(string message)
{
do
{
//_speechRecongnitionInstance.StopSpeechToText();
//_speechRecongnitionInstance.StartSpeechToText();
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceivePassword);
}
private bool CheckMicrophone()
{
string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec != "android.hardware.microphone")
{
// no microphone, no recording. Disable the button and output an alert
DisplayAlert("Error", CommonData.GetMessage(MessageCode.SettingSaveSuccess), "OK");
btnSpeak.IsEnabled = false;
return false;
}
return true;
}
private async Task RequestUsername(string message = "")
{
_field = "Username";
isReceiveUsername = false;
txtUsername.Text = string.Empty;
lblDisplayname.Text = string.Empty;
txtUsername.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputUsername) : message);
Task.Run(() => RepeatVoiceUsername(message));
_speechRecongnitionInstance.StartSpeechToText(_field);
}
private async Task RequestPassword(string message = "")
{
_field = "Password";
isReceivePassword = false;
txtPassword.Text = string.Empty;
lblDisplayname.Text = string.Empty;
txtPassword.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputPassword) : message);
Task.Run(() => RepeatVoicePassword(message));
_speechRecongnitionInstance.StartSpeechToText(_field);
}
}
}
2. The Speech Recognizer class:
using Android.App;
using Android.Content;
using Android.Speech;
using Java.Util;
using Plugin.CurrentActivity;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo.Speech
{
public class SpeechToTextImplementation
{
public static AutoResetEvent autoEvent = new AutoResetEvent(false);
private readonly int VOICE = 10;
private Activity _activity;
private float _timeOut = 3;
private string _text;
public SpeechToTextImplementation()
{
_activity = CrossCurrentActivity.Current.Activity;
}
public SpeechToTextImplementation(string text)
{
_text = text;
_activity = CrossCurrentActivity.Current.Activity;
}
public string Language;
public void StartSpeechToText()
{
StartRecordingAndRecognizing();
}
public void StartSpeechToText(string text)
{
_text = text;
StartRecordingAndRecognizing();
}
private async void StartRecordingAndRecognizing()
{
string rec = global::Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec == "android.hardware.microphone")
{
try
{
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
Intent voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, _text);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
_activity.StartActivityForResult(voiceIntent, VOICE);
await Task.Run(() => { autoEvent.WaitOne(new TimeSpan(0, 2, 0)); });
}
catch (ActivityNotFoundException ex)
{
String appPackageName = "com.google.android.googlequicksearchbox";
try
{
Intent intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse("market://details?id=" + appPackageName));
_activity.StartActivityForResult(intent, VOICE);
}
catch (ActivityNotFoundException e)
{
Intent intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse("https://play.google.com/store/apps/details?id=" + appPackageName));
_activity.StartActivityForResult(intent, VOICE);
}
}
}
else
{
throw new Exception("No mic found");
}
}
public void StopSpeechToText()
{
// Do something here to close the service
}
}
}
3. MainActivity:
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Speech;
using MauiDemo.Common;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
namespace MauiDemo
{
[Activity(Label = "Maui Demo", Theme = "#style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity, IMessageSender
{
private readonly int VOICE = 10;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == VOICE)
{
if (resultCode == Result.Ok)
{
var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
if (matches.Count != 0)
{
string textInput = matches[0];
MessagingCenter.Send<IMessageSender, string>(this, "STT", textInput);
}
else
{
MessagingCenter.Send<IMessageSender, string>(this, "STT", "");
}
}
}
base.OnActivityResult(requestCode, resultCode, data);
}
}
}
4. MainApplication
using Android.App;
using Android.OS;
using Android.Runtime;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using Plugin.CurrentActivity;
using System;
namespace MauiDemo
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
public override void OnCreate()
{
base.OnCreate();
CrossCurrentActivity.Current.Init(this);
}
public override void OnTerminate()
{
base.OnTerminate();
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
}
After struggle for a few days without any success, I found a new way to do this thing by using SpeechRecognizer class, instead of using a Google service. With this, I am able to have a better control on the process.
To use SpeechRecognizer, I copied the code in "Create platform microphone services" for permission from this Microsoft page: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/azure-cognitive-services/speech-recognition
I have update my code as below:
Login page: currently is named Prototype2.
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MauiDemo.View
{
public partial class Prototype2 : ContentPage
{
private string _field = string.Empty;
private int _waitTime = 2000;
public List<Language> Languages { get; }
private SpeechToTextImplementation2 _speechRecognizer;
//private BackgroundWorker worker = new BackgroundWorker();
private struct VoiceMode
{
int Username = 1;
int Password = 2;
}
public Prototype2()
{
InitializeComponent();
this.lblTitle.Text = "Prototype2" + App.Status;
CheckMicrophone();
CommonData.CurrentField = string.Empty;
try
{
_speechRecognizer = new SpeechToTextImplementation2();
_speechRecognizer.Language = DefaultData.SettingLanguage;
}
catch (Exception ex)
{
DisplayAlert("Error", ex.Message, "OK");
}
MessagingCenter.Subscribe<ISpeechToText, string>(this, "STT", (sender, args) =>
{
ReceivedUsernameAsync(args);
});
MessagingCenter.Subscribe<ISpeechToText>(this, "Final", (sender) =>
{
btnSpeak.IsEnabled = true;
});
MessagingCenter.Subscribe<IMessageSender, string>(this, "STT", (sender, args) =>
{
SpeechToTextRecievedAsync(args);
});
isReceiveUsername = false;
isReceivePassword = false;
RequestUsername(true);
}
protected override void OnDisappearing()
{
CommonData.CurrentField = string.Empty;
base.OnDisappearing();
}
private async void btnSpeak_Clicked(Object sender, EventArgs e)
{
isReceiveUsername = false;
isReceivePassword = false;
await RequestUsername(true);
}
private async void SpeechToTextRecievedAsync(string args)
{
switch (_field)
{
case "Username":
await this.ReceivedUsernameAsync(args);
break;
case "Password":
await this.ReceivedPasswordAsync(args);
break;
}
}
bool isReceiveUsername = false;
bool isReceivePassword = false;
private async Task ReceivedUsernameAsync(string args)
{
txtUsername.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtUsername.Text))
{
isReceiveUsername = false;
}
else
{
isReceiveUsername = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()));
if (checkUser.Any())
{
await RequestPassword(true);
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongUsername);
lblMessage.Text = message;
isReceiveUsername = false;
await RequestUsername(false, message);
}
}
}
private async Task ReceivedPasswordAsync(string args)
{
txtPassword.Text = args.Replace(" ", string.Empty);
lblMessage.Text = string.Empty;
if (string.IsNullOrWhiteSpace(txtPassword.Text))
{
isReceivePassword = false;
}
else
{
isReceivePassword = true;
var checkUser = DefaultData.Users.Where(x => x.Username.ToLower().Equals(txtUsername.Text.ToLower()) && x.Password.Equals(txtPassword.Text));
if (checkUser.Any())
{
_field = "";
lblDisplayname.Text = checkUser.FirstOrDefault().Displayname;
string msg = CommonData.GetMessage(MessageCode.LoginSuccess);
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
msg
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
await Navigation.PushAsync(new MainPage());
}
else
{
string message = CommonData.GetMessage(MessageCode.WrongPassword);
lblMessage.Text = message;
isReceivePassword = false;
await RequestPassword(false, message);
}
}
}
private async Task RepeatVoiceUsername(string message)
{
do
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceiveUsername);
}
private async Task RepeatVoicePassword(string message)
{
do
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
Thread.Sleep(_waitTime);
}
while (!isReceivePassword);
}
private bool CheckMicrophone()
{
string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec != "android.hardware.microphone")
{
// no microphone, no recording. Disable the button and output an alert
DisplayAlert("Error", CommonData.GetMessage(MessageCode.SettingSaveSuccess), "OK");
btnSpeak.IsEnabled = false;
return false;
}
return true;
}
private async Task RequestUsername(bool isRepeat, string message = "")
{
_field = "Username";
isReceiveUsername = false;
//txtUsername.Text = string.Empty;
//lblDisplayname.Text = string.Empty;
txtUsername.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputUsername) : message);
if (isRepeat)
{
Task.Run(() => RepeatVoiceUsername(message));
}
else
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
}
_speechRecognizer.StartListening();
}
private async Task RequestPassword(bool isRepeat, string message = "")
{
_field = "Password";
isReceivePassword = false;
//txtPassword.Text = string.Empty;
//lblDisplayname.Text = string.Empty;
txtPassword.Focus();
message = (message.IsNullOrWhiteSpace() ? CommonData.GetMessage(MessageCode.InputPassword) : message);
if (isRepeat)
{
Task.Run(() => RepeatVoicePassword(message));
}
else
{
await Plugin.TextToSpeech.CrossTextToSpeech.Current.Speak(
message
, crossLocale: CommonData.GetCrossLocale(DefaultData.SettingLanguage)
, speakRate: DefaultData.SettingSpeed
, pitch: DefaultData.SettingPitch
);
}
_speechRecognizer.StartListening();
}
}
}
New Microphone Service to handle the permission
using Android.App;
using Android.Content.PM;
using Android.OS;
using AndroidX.Core.App;
using Google.Android.Material.Snackbar;
using System.Threading.Tasks;
namespace MauiDemo.Speech
{
public class MicrophoneService
{
public const int RecordAudioPermissionCode = 1;
private TaskCompletionSource<bool> tcsPermissions;
string[] permissions = new string[] { Manifest.Permission.RecordAudio };
public MicrophoneService()
{
tcsPermissions = new TaskCompletionSource<bool>();
}
public Task<bool> GetPermissionAsync()
{
if ((int)Build.VERSION.SdkInt < 23)
{
tcsPermissions.TrySetResult(true);
}
else
{
var currentActivity = MainActivity.Instance;
if (ActivityCompat.CheckSelfPermission(currentActivity, Manifest.Permission.RecordAudio) != (int)Permission.Granted)
{
RequestMicPermissions();
}
else
{
tcsPermissions.TrySetResult(true);
}
}
return tcsPermissions.Task;
}
public void OnRequestPermissionResult(bool isGranted)
{
tcsPermissions.TrySetResult(isGranted);
}
void RequestMicPermissions()
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(MainActivity.Instance, Manifest.Permission.RecordAudio))
{
Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content),
"Microphone permissions are required for speech transcription!",
Snackbar.LengthIndefinite)
.SetAction("Ok", v =>
{
((Activity)MainActivity.Instance).RequestPermissions(permissions, RecordAudioPermissionCode);
})
.Show();
}
else
{
ActivityCompat.RequestPermissions((Activity)MainActivity.Instance, permissions, RecordAudioPermissionCode);
}
}
}
}
New Speech=>Text class to use SpeechRecognizer: Mostly take frrm this How to increase the voice listen time in Google Recognizer Intent(Speech Recognition) Android
using Android;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Speech;
using AndroidX.Core.App;
using Java.Util;
using MauiDemo.Common;
using Microsoft.Maui.Controls;
using Plugin.CurrentActivity;
using System.Threading;
namespace MauiDemo.Speech
{
public class SpeechToTextImplementation2 : Java.Lang.Object, IRecognitionListener, IMessageSender
{
public static AutoResetEvent autoEvent = new AutoResetEvent(false);
private readonly int VOICE = 10;
private Activity _activity;
private float _timeOut = 3;
private SpeechRecognizer _speech;
private Intent _speechIntent;
public string Words;
public string Language;
private MicrophoneService micService;
public SpeechToTextImplementation2()
{
micService = new MicrophoneService();
_activity = CrossCurrentActivity.Current.Activity;
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._activity);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
}
void RestartListening()
{
var locale = Locale.Default;
if (!string.IsNullOrWhiteSpace(Language))
{
locale = new Locale(Language);
}
_speech.Destroy();
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._activity);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, _timeOut * 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguage, locale.ToString());
StartListening();
}
public async void StartListening()
{
bool isMicEnabled = await micService.GetPermissionAsync();
if (!isMicEnabled)
{
Words = "Please grant access to the microphone!";
return;
}
_speech.StartListening(_speechIntent);
}
public void StopListening()
{
_speech.StopListening();
}
public void OnBeginningOfSpeech()
{
}
public void OnBufferReceived(byte[] buffer)
{
}
public void OnEndOfSpeech()
{
}
public void OnError([GeneratedEnum] SpeechRecognizerError error)
{
Words = error.ToString();
MessagingCenter.Send<IMessageSender, string>(this, "Error", Words);
RestartListening();
}
public void OnEvent(int eventType, Bundle #params)
{
}
public void OnPartialResults(Bundle partialResults)
{
}
public void OnReadyForSpeech(Bundle #params)
{
}
public void OnResults(Bundle results)
{
var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
if (matches == null)
Words = "Null";
else
if (matches.Count != 0)
Words = matches[0];
else
Words = "";
MessagingCenter.Send<IMessageSender, string>(this, "STT", Words);
RestartListening();
}
public void OnRmsChanged(float rmsdB)
{
}
}
}
Update MainActivities for permission
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Speech;
using MauiDemo.Common;
using MauiDemo.Speech;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
namespace MauiDemo
{
[Activity(Label = "Maui Demo", Theme = "#style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity, IMessageSender
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Instance = this;
micService = new MicrophoneService();
}
private readonly int VOICE = 10;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == VOICE)
{
if (resultCode == Result.Ok)
{
var matches = data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
if (matches.Count != 0)
{
string textInput = matches[0];
MessagingCenter.Send<IMessageSender, string>(this, "STT", textInput);
}
else
{
MessagingCenter.Send<IMessageSender, string>(this, "STT", "");
}
//SpeechToTextImplementation.autoEvent.Set();
}
}
base.OnActivityResult(requestCode, resultCode, data);
}
MicrophoneService micService;
internal static MainActivity Instance { get; private set; }
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
// ...
switch (requestCode)
{
case MicrophoneService.RecordAudioPermissionCode:
if (grantResults[0] == Permission.Granted)
{
micService.OnRequestPermissionResult(true);
}
else
{
micService.OnRequestPermissionResult(false);
}
break;
}
}
}
}
Feel free to check out the code, but I will not use this for anything serious because it does not runs properly yet.
Any opinion to improve for the code will be really appreciated, as I really want to get good with this MAUI platform.

Xamarin picker not showing the date from the list

I have the following code:
<ContentPage.BindingContext>
<local:PisterosViewModel/>
</ContentPage.BindingContext>
<Picker x:Name="pck_Pisteros"
ItemDisplayBinding="{Binding PisteroN}"
ItemsSource="{Binding PisterosLista}"
SelectedItem="{Binding PisterosLista}"
Title="Seleccione el usuario..."/>
Then my Model:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Text;
namespace ServLottery.Models
{
public class Pisteros
{
public string PisteroID { get; set; }
public string PisteroN { get; set; }
}
}
and the view model:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace ServLottery.Models
{
public class PisterosViewModel
{
public IList<Pisteros> PisterosLista { get; set; }
public PisterosViewModel()
{
try
{
PisterosLista = new ObservableCollection<Pisteros>();
GetPisteros();
}
catch (Exception ex)
{
throw ex;
}
}
private async void GetPisteros()
{
try
{
RestClient client = new RestClient();
var pist = await client.Get<Models.Pisteros>("https://servicentroapi.azurewebsites.net/api/Pisteros");
if (pist != null)
{
PisterosLista = pist;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
I set an breakpoint in var pist and it does have the values, then Pisteros list seems to get the values too, and this is executed when the page load, so I don't understand what's the problem, but the picker never shows the options.
Welcome to SO !
It seems like BindingContext in Xaml can not deal with the dynamical data ,such API data from web server .
There is a workaround binding ItemSource dynamically by using coding in ContentPage , also can refer to this officail sample .
Therefore , adding code in Page.Xaml.cs as follow :
protected override async void OnAppearing()
{
pck_Pisteros.ItemsSource = await GetTasksAsync();
base.OnAppearing();
}
private async Task<List<Pisteros>> GetTasksAsync()
{
List<Pisteros> PisterosLista = new List<Pisteros>();
HttpClient client = new HttpClient();
Uri uri = new Uri(string.Format("https://servicentroapi.azurewebsites.net/api/Pisteros", string.Empty));
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
PisterosLista = JsonConvert.DeserializeObject<List<Pisteros>>(content);
Console.WriteLine("content :: " + content);
Console.WriteLine("Data :: " + PisterosLista);
}
return PisterosLista;
}
Now it will show:

How to set Title of Tab with MVVMCross 6.2?

I'm trying to figure out how to properly set the localized string as Tab Title (or dynamically change the Tab Title) with MVVMCross 6.2+ in Xamarin Android.
How should I set the title of the tab in the simple example app?
Thanks in advance for your help.
Here is the simple example app:
MvvmCrossTabs.Core
HomeViewModel.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using MvvmCross.Commands;
using MvvmCross.Logging;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace MvvmCrossTabs.Core.ViewModels
{
public class HomeViewModel : MvxNavigationViewModel
{
public IMvxAsyncCommand ShowInitialViewModelsCommand { get; private set; }
public HomeViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService)
{
ShowInitialViewModelsCommand = new MvxAsyncCommand(ShowInitialViewModels);
}
private async Task ShowInitialViewModels()
{
await Task.WhenAll(new List<Task>
{
NavigationService.Navigate<Tab1ViewModel>(),
NavigationService.Navigate<Tab2ViewModel>(),
NavigationService.Navigate<Tab3ViewModel>()
});
}
}
}
Tab1ViewModel.cs (Tab2ViewModel.cs, Tab3ViewModel.cs)
using MvvmCross.Logging;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
namespace MvvmCrossTabs.Core.ViewModels
{
public class Tab1ViewModel : MvxNavigationViewModel
{
public Tab1ViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService)
{
}
}
}
App.cs
using MvvmCross.IoC;
using MvvmCross.ViewModels;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Core
{
public class App : MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<HomeViewModel>();
}
}
}
MvvmCrossTabs.Android
MainApplication.cs
using System;
using Android.App;
using Android.Runtime;
using MvvmCross.Droid.Support.V7.AppCompat;
using MvvmCrossTabs.Core;
namespace MvvmCrossTabs.Android
{
[Application]
public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
{
public MainApplication() : base() { }
public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }
}
}
home.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/maincontent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="enterAlways"
app:tabGravity="fill"
app:tabMaxWidth="0dp" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
tab1.axml (tab2.axml, tab3.axml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_frame"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
HomeView.cs
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Support.V7.Widget;
using MvvmCross.Droid.Support.V7.AppCompat;
using MvvmCross.Platforms.Android.Presenters.Attributes;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Android
{
[Activity(Label = "#string/app_name", LaunchMode = LaunchMode.SingleTask, Theme = "#style/AppTheme", MainLauncher = true)]
[MvxActivityPresentation]
public class HomeView : MvxAppCompatActivity<HomeViewModel>
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.home);
// Replaces Action Bar with new Toolbar.
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
ViewModel.ShowInitialViewModelsCommand.Execute();
}
}
}
Tab1View.cs (Tab2View.cs, Tab3View.cs)
using Android.OS;
using Android.Runtime;
using Android.Views;
using MvvmCross.Droid.Support.V4;
using MvvmCross.Platforms.Android.Binding.BindingContext;
using MvvmCross.Platforms.Android.Presenters.Attributes;
using MvvmCrossTabs.Core.ViewModels;
namespace MvvmCrossTabs.Android.Views
{
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", ActivityHostViewModelType = typeof(HomeViewModel))]
[Register(nameof(Tab1View))]
public class Tab1View : MvxFragment<Tab1ViewModel>
{
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.tab1, null);
}
}
}
When your tabs are created using the ShowInitialViewModelsCommand, the built-in presenter creates a list of MvxViewPagerFragmentInfo objects, passing in the Title value from the attributes. You can see that happening in the ShowViewPagerFragment method in the MvvmCross source code.
The list of MvxViewPagerFragmentInfo objects is then passed into the MvxCachingFragmentStatePagerAdapter that is created for the ViewPager. You can see that happening here
MvxCachingFragmentStatePagerAdapter inherits from the MvxFragmentPagerAdapter class. Inside the MvxFragmentPagerAdapter class is finally where the Title you provided is actually used. You can see it being used in the GetPageTitleFormatted method here
So in order to change the Title at runtime, you could do the following:
Subclass the default presenter and override the ShowViewPagerFragment method (it is marked virtual) and provide the correct localized title string instead of the one defined in the attribute
Here is an example of how to accomplish this:
1.) Create a custom presenter and override ShowViewPagerFragment
public class LocalizedTabPresenter : MvxAppCompatViewPresenter
{
public LocalizedTabPresenter(IEnumerable<Assembly> androidViewAssemblies) : base(androidViewAssemblies)
{
}
protected override Task<bool> ShowViewPagerFragment(Type view, MvxViewPagerFragmentPresentationAttribute attribute, MvxViewModelRequest request)
{
if (attribute.ViewModelType == typeof(Tab1ViewModel)) {
attribute.Title = "My Localized Title for Tab 1"
}
return base.ShowViewPagerFragment(view, attribute, request);
}
}
2.) In your Setup.cs class, let MvvmCross know to use the custom presenter instead
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
return new LocalizedTabPresenter(AndroidViewAssemblies);
}
Note:
This will only work if you need to set the title only once when the
app launches and is setting up the tabs for the first time.
If you are in a situation where the Title can change multiple times while the app is running, you need to subclass MvxCachingFragmentStatePagerAdapter and override the GetPageTitleFormatted method and provide a more custom implementation that fits your use case.
Hope that helps.
Another possible solution would be to use the IMvxOverridePresentationAttribute interface.
This way you can change these values at runtime from the fragment itself.
To do it, simply implement IMvxOverridePresentationAttribute in your tab fragment, and then return something like this:
public MvxBasePresentationAttribute PresentationAttribute(MvxViewModelRequest request)
{
return new MvxTabLayoutPresentationAttribute(title: _("Results"), viewPagerResourceId: Resource.Id.viewPager, tabLayoutResourceId: Resource.Id.tab_layout, fragmentHostViewType: typeof(HostFragment));
}
I like this approach because I don't need to change anything at app level and I have all the code related to the fragment contained in that fragment specifically.
I've been using this and it has been working perfectly.
Be aware that this.ViewModel property will be null during PresentationAttribute
If you want a more detailed explanation on how it works, have a look at this
You have to do something like that:
if (fragments == null || fragments.Count == 0)
{
_firstFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_firstFragment.ViewModel = YourVM;
_secondFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_secondFragment.ViewModel = YourVM;
_thridFragment= (YourFragmentType)Activator.CreateInstance(typeof(YourFragmentType));
_thridFragment.ViewModel = YourVM;
// Strings from RESX Localization
fragments = new Dictionary<string, Fragment>
{
{ Strings.first_localized_string, _firstFragment},
{ Strings.second_localized_string, _secondFragment},
{ Strings.thrid_localized_string, _thridFragment}
};
}
viewPager = View.FindViewById<ViewPager>(Resource.Id.viewpager);
adapter = new TabsFragmentPagerAdapter(ChildFragmentManager, fragments);
viewPager.Adapter = adapter;
var tabLayout = View.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
Your adapter:
public class TabsFragmentPagerAdapter : FragmentPagerAdapter
{
private readonly Fragment[] fragments;
private readonly string[] titles;
public TabsFragmentPagerAdapter(FragmentManager fm, Dictionary<string, Fragment> fragments) : base(fm)
{
this.fragments = fragments.Values.ToArray();
this.titles = fragments.Keys.ToArray();
}
public override int Count => fragments.Length;
private String GetCharSeuenceFromString(string s)
{
return new String(s);
}
public override Object InstantiateItem(ViewGroup container, int position)
{
return base.InstantiateItem(container, position);
}
public override void SetPrimaryItem(ViewGroup container, int position, Object #object)
{
base.SetPrimaryItem(container, position, #object);
}
public override Fragment GetItem(int position)
{
return fragments[position];
}
public override ICharSequence GetPageTitleFormatted(int position)
{
return GetCurrentPageTitle(position);
}
private ICharSequence GetCurrentPageTitle(int position)
{
return GetCharSeuenceFromString(titles[position]);
}
}
Happy codding!
P.S. Don't use fragments with generics.

Android Widget works in debug but not in release

I coded an Android widget which works perfectly fine during debugging, but after the release, it seems like the AppWidget.cs-Program doesn't get called because I can only see what I created in the Layout.
This program is made for activating or deactivating a lamp which reacts when the program calls the site, for example: "http://192.168.0.52/ein" activates the lamp, "http://192.168.0.52/aus" deactivates the lamp, and "http://192.168.0.52/state" gets the current status ("on" or "off") of the lamp. Thank you in advance!
AppWidget.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Android.App;
using Android.Appwidget;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace OrigWidget
{
[BroadcastReceiver(Label = "IoT-Lampe")]
[IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })]
[MetaData("android.appwidget.provider", Resource = "#xml/appwidgetprovider")]
public class AppWidget : AppWidgetProvider
{
WebClient client;
RemoteViews widgetView;
AppWidgetManager awm;
Context c;
int[] aWid;
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
awm = appWidgetManager;
c = context;
aWid = appWidgetIds;
System.Threading.Timer t = new System.Threading.Timer(upd, null, 0, 5000);
}
private void upd(Object o)
{
var me = new ComponentName(c, Java.Lang.Class.FromType(typeof(AppWidget)).Name);
awm.UpdateAppWidget(me, BuildRemoteViews(c, aWid));
}
private RemoteViews BuildRemoteViews(Context context, int[] appWidgetIds)
{
widgetView = new RemoteViews(context.PackageName, Resource.Layout.Widget);
SetTextViewText(widgetView);
RegisterClicks(context, appWidgetIds, widgetView);
return widgetView;
}
private void SetTextViewText(RemoteViews widgetView)
{
Check();
}
public void Check()
{
client = new WebClient();
String htmlText = client.DownloadString("http://192.168.0.52/state");
client.Dispose();
if (htmlText == "on")
{
widgetView.SetInt(Resource.Id.an, "setBackgroundColor", Color.LimeGreen);
widgetView.SetInt(Resource.Id.aus, "setBackgroundColor", Color.Rgb(71, 66, 65));
}
else if (htmlText == "off")
{
widgetView.SetInt(Resource.Id.an, "setBackgroundColor", Color.Rgb(71, 66, 65));
widgetView.SetInt(Resource.Id.aus, "setBackgroundColor", Color.Red);
}
}
private static string AusClick = "AusClickTag";
private static string AnClick = "AnClickTag";
public override void OnReceive(Context context, Intent intent)
{
base.OnReceive(context, intent);
if (AnClick.Equals(intent.Action))
{
try
{
client = new WebClient();
String unnecessary = client.DownloadString("http://192.168.0.52/ein");
String nec = client.DownloadString("http://192.168.0.52/state");
client.Dispose();
}
catch (Exception) { }
}
if (AusClick.Equals(intent.Action))
{
try
{
client = new WebClient();
String unnecessary = client.DownloadString("http://192.168.0.52/aus");
client.Dispose();
}
catch (Exception) { }
}
}
private void RegisterClicks(Context context, int[] appWidgetIds, RemoteViews widgetView)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(AppWidgetManager.ActionAppwidgetUpdate);
intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, appWidgetIds);
widgetView.SetOnClickPendingIntent(Resource.Id.an, GetPendingSelfIntent(context, AnClick));
widgetView.SetOnClickPendingIntent(Resource.Id.aus, GetPendingSelfIntent(context, AusClick));
}
private PendingIntent GetPendingSelfIntent(Context context, string action)
{
var intent = new Intent(context, typeof(AppWidget));
intent.SetAction(action);
return PendingIntent.GetBroadcast(context, 0, intent, 0);
}
}
}

Logging in Android App Using the data from database of ASP.net C#

I already used SOAP for getting the Idnumber from the database of ASp.net C# and I created an App that he/she can log using Email and Password and will go to next activity. This is the code that is used for trying to logged in using the Email and Password in WebSite.
public class MainActivity extends Activity {
EditText Email, Password;
Button button;
TextView error;
String EmailAddfromWeb, PassfromWeb;
private static final String SOAP_ACTION = "http://tempuri.org/findContact";
private static final String OPERATION_NAME = "CheckLogin";
private static final String WSDL_TARGET_NAMESPACE = "http://tempuri.org/";
private static final String SOAP_ADDRESS = "http://10.0.2.2:64485/WebService.asmx";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Email = (EditText)findViewById(R.id.editText1);
Password = (EditText)findViewById(R.id.editText2);
button = (Button)findViewById(R.id.button1);
error = (TextView)findViewById(R.id.textView3);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v){
SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE, OPERATION_NAME);
PropertyInfo propertyInfo = new PropertyInfo();
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "EmailAdd";
EmailAddfromWeb = Email.getText().toString();
request.addProperty(propertyInfo, EmailAddfromWeb);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
try
{
httpTransport.call(SOAP_ACTION, envelope);
Object response = envelope.getResponse();
error.setText(response.toString());
SPLPVIEWER s = new SPLPVIEWER();
Intent intent = new Intent(MainActivity.this, SPLPVIEWER.class);
Bundle b = new Bundle();
b.putString(s.holder, "" + String.valueOf(Email));
intent.putExtras(b);
startActivity(intent);
finish();
}
catch(Exception e)
{
error.setText("Invalid Email!");
}
}
});
Code for WebService.asmx.cs :
How can i compare my data login in Web Service from the inputted in AndroidApplication.
using System;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Data.SqlClient;
using System.Data;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
public WebService()
{
}
[WebMethod]
public bool CheckLogin(string EmailAdd, string Password)
{
return getEmail(EmailAdd, Password);
}
public bool getEmail(String EmailAdd, String Password)
{
SqlConnection conn;
conn = ConnectionManager.GetConnection();
conn.Open();
bool check = false;
string pa;
SqlCommand CheckCmd = new SqlCommand("CheckEmailAddress", conn);
CheckCmd.CommandType = CommandType.StoredProcedure;
CheckCmd.Parameters.Add("#EmailAddress", SqlDbType.NVarChar).Value = EmailAdd;
SqlDataReader sdr = CheckCmd.ExecuteReader();
while (sdr.Read())
{
pa = sdr.GetString(8); // for Password column
if (pa == Password)
{
check = true;
}
break;
}
conn.Close();
return check;
}
}
use asp Web service or simple post methods.
Try this http://www.androidhive.info/2011/11/android-xml-parsing-tutorial/
Build your xml page via asp.net.

Categories