Adding "rate my app" to Web App Template - windows-phone-8

There's a project called Web App Template (aka WAT - http://wat.codeplex.com/) that allows you to wrap a webapp as a Windows 8 / Windows Phone 8 application. I've done that to an app, now I'm trying to add the "rate my app" feature to it. I don't see where/if I can inject code for this component to be added.
I'm following a guide here: http://developer.nokia.com/community/wiki/Implement_%22Rate_My_App%22_in_under_60_seconds
I'm stuck at Step 5 - where do I add the Event Handler? There is no MainPage.xaml.cs and I don't see any similar files.
I imagine that WAT is calling another library to load a web browser. Is there some way I can inject an Event Handler and method into this library?

I suggest not to prompt the user with 'rate my app' thing in the first opening of the app as user should be given some time to see what the app looks like and how it functions. Therefore, keeping the number of app launches and asking to rate the app after some 5th - 10th launch of app will make more sense. Besides you should check if you already prompted the user to rate your app, if so never prompt again. (Otherwise you will piss them off with 'rate my app' thing)
In order to achieve this, you should at first keep the app launch count in app settings class.
The interface for storing any kind of setting:
public interface ISettingService
{
void Save();
void Save(string key, object value);
bool AddOrUpdateValue(string Key, object value);
bool IsExist(string key);
T Load<T>(string key);
T GetValueOrDefault<T>(string Key, T defaultValue);
}
The rating service class that consumes the above interface to store such count and settings:
public class RatingService
{
private const string IsAppRatedKeyName = "isApprated";
private const string TabViewCountKeyName = "tabViewCount";
private const bool IsAppratedDefault = false;
private const int TabViewCountDefault = 0;
private const int ShowRatingInEveryN = 7;
private readonly ISettingService _settingService;
[Dependency]
public RatingService(ISettingService settingService)
{
_settingService = settingService;
}
public void RateApp()
{
if (_settingService.AddOrUpdateValue(IsAppRatedKeyName, true))
_settingService.Save();
}
public bool IsNeedShowMessage()
{
return (_settingService.GetValueOrDefault(TabViewCountKeyName, TabViewCountDefault)%ShowRatingInEveryN) == 0;
}
public void IncreaseTabViewCount()
{
int tabCount = _settingService.GetValueOrDefault(TabViewCountKeyName, TabViewCountDefault);
if (_settingService.AddOrUpdateValue(TabViewCountKeyName, (tabCount + 1)))
_settingService.Save();
}
public bool IsAppRated()
{
return _settingService.GetValueOrDefault(IsAppRatedKeyName, IsAppratedDefault);
}
}
This is how you will run such functionality and prompt the user to rate the app (if previously not rated) anywhere in your project (mainpage or some other page where user launches some functionality):
private void RunRating()
{
if (!RatingService.IsAppRated() && RatingService.IsNeedShowMessage())
{
MessageBoxResult result = MessageBox.Show("Review the app?", "Would you like to review this awesome app?",
MessageBoxButton.OKCancel);
//show message.
if (result == MessageBoxResult.OK)
{
RatingService.RateApp();
new MarketplaceReviewTask().Show();
}
}
}

Related

How to Authorize user on winforms when connecting to telegram

If i run this code on console application:
static async Task Main(string[] _)
{
using var client = new WTelegram.Client();
var user = await client.LoginUserIfNeeded();
Console.WriteLine($"We are logged-in as {user.username ?? user.first_name + " " + user.last_name} (id {user.id})");
}
It will prompt interactively for App api_id and api_hash.
How can i Authorize user on winforms application?. So that i can input the api_id and api_hash through textbox
Edit: (Oct 2022) Latest version of the library has a simplified config system that makes it more easy to use in WinForms apps.
Please take a look at the example WinForms app provided in the repository that demonstrate how to proceed.
The original answer below is still valid but maybe more complex
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
First, you should read WTelegramClient FAQ #3:
3. How to use the library in a WinForms or WPF application
The library should work without a problem in a GUI application.
The difficulty might be in your Config callback when the user must enter the verification code or password, as you can't use Console.ReadLine here.
An easy solution is to call Interaction.InputBox("Enter verification code") instead.
This might require adding a reference (and using) to the Microsoft.VisualBasic assembly.
A more complex solution requires the use of a ManualResetEventSlim that you will wait for in Config callback,
and when the user has provided the verification_code through your GUI, you "set" the event to release your Config callback so it can return the code.
Here is an example solution for your Form class with a ManualResetEventSlim and textboxes:
using Microsoft.VisualBasic;
using TL;
private readonly ManualResetEventSlim _codeReady = new ManualResetEventSlim();
private WTelegram.Client _client;
private User _user;
string Config(string what)
{
switch (what)
{
case "api_id": return textBoxApiID.Text;
case "api_hash": return textBoxApiHash.Text;
case "phone_number": return textBoxPhone.Text;
case "verification_code":
_codeReady.Reset();
_codeReady.Wait();
return textBoxCode.Text;
case "password": return Interaction.InputBox("Enter 2FA password");
default: return null;
};
}
private void textBoxCode_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\r') // pressing Return in the textboxCode
{
_codeReady.Set();
e.Handled = true;
}
}
private async void buttonLogin_Click(object sender, EventArgs e)
{
buttonLogin.Enabled = false;
_client = new WTelegram.Client(Config);
_user = await _client.LoginUserIfNeeded();
MessageBox.Show("We are now connected as " + _user);
}
private async void buttonGetChats_Click(object sender, EventArgs e)
{
if (_user == null) { MessageBox.Show("You must complete the login first."); return; }
var chats = await _client.Messages_GetAllChats(null);
MessageBox.Show(string.Join("\n", chats.chats.Values.Where(c => c.IsActive)));
}

AutoMapper - passing parameter to custom resolver weird behavior

Although I'm relatively new to AutoMapper I'm using it in a small project I'm developing. I've never had problems using it before but now I'm facing some weird behavior passing parameters to a Custom Resolver.
Here's the scenario: I get a list of messages from my repository and then map those to a frontend friendly version of it. Nothing fancy, just some normal mapping between objects. I have a field in that frontend object that tells if a certain user already voted for that message and that's what I'm using the Custom Resolver for (it's that second "ForMember"):
public List<SupportMessageUi> GetAllVisible(string userId)
{
Mapper.CreateMap<SupportMessage, SupportMessageUi>()
.ForMember(dest => dest.Votes,
opt => opt.ResolveUsing<SupportMessageVotesResolver>())
.ForMember(dest => dest.UserVoted,
opt => opt.ResolveUsing<SupportMessagesUserVotedResolver>()
.ConstructedBy(() => new SupportMessagesUserVotedResolver(userId)));
var messages = _unitOfWork.MessagesRepository.Get(m => m.Visible);
var messagesUi = Mapper.Map<List<SupportMessageUi>>(messages);
return messagesUi;
}
I'm calling this method on a web service and the problem is: the first time I call the webservice (using the webservice console) it all runs perfectly. For example, if I pass '555' as the userId I get to this method with the correct value:
And in the Custom Resolver the value was correctly passed to the constructor:
The results returned are correct. The problem comes next. The second time I call the service, passing a different argument ('666' this time) the argument that gets to the constructor of the Custom Resolver is the old one ('555'). Here's what I mean:
Right before mapping the objects we can see that the value passed to the constructor was correct ('666'):
But when it gets to the constructor of the Resolver the value is wrong, and is the old one ('555'):
All subsequent calls to the service use the original value in the Custom Resolver constructor ('555'), independently of the value I pass to the service (also happens if I make the call from another browser). If I shut down the server and relaunch it I can pass a new parameter (that will be used in all other calls until I shut it down again).
Any idea on why this is happening?
It's happening because AutoMapper.CreateMap is a static method, and only needs to be called once. With the CreateMap code in your web method, you're trying to call it every time you call that method on your web service. Since the web server process stays alive between calls (unless you restart it, like you said) then the static mappings stay in place. Hence, the necessity of calling AutoMapper.Reset, as you said in your answer.
But it's recommended that you put your mapping creation in AppStart or Global or a static constructor or whatever, so you only call it once. There are ways to call Map that allow you to pass in values, so you don't need to try to finesse things with the constructor of your ValueResolver.
Here's an example using a ValueResolver (note the change to implementing IValueResolver instead of inheriting ValueResolver<TSource, TDestination>):
[Test]
public void ValueTranslator_ExtraMapParameters()
{
const int multiplier = 2;
ValueTranslator translator = new ValueTranslator();
Mapper.AssertConfigurationIsValid();
ValueSource source = new ValueSource { Value = 4 };
ValueDest dest = translator.Translate(source, multiplier);
Assert.That(dest.Value, Is.EqualTo(8));
source = new ValueSource { Value = 5 };
dest = translator.Translate(source, multiplier);
Assert.That(dest.Value, Is.EqualTo(10));
}
private class ValueTranslator
{
static ValueTranslator()
{
Mapper.CreateMap<ValueSource, ValueDest>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing<ValueResolver>().FromMember(src => src.Value));
}
public ValueDest Translate(ValueSource source, int multiplier)
{
return Mapper.Map<ValueDest>(source, opt => opt.Items.Add("multiplier", multiplier));
}
private class ValueResolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
return source.New((int)source.Value * (int)source.Context.Options.Items["multiplier"]);
}
}
}
private class ValueSource { public int Value { get; set; } }
private class ValueDest { public int Value { get; set; } }
And here's an example using a TypeConverter:
[Test]
public void TypeTranslator_ExtraMapParameters()
{
const int multiplier = 3;
TypeTranslator translator = new TypeTranslator();
Mapper.AssertConfigurationIsValid();
TypeSource source = new TypeSource { Value = 10 };
TypeDest dest = translator.Translate(source, multiplier);
Assert.That(dest.Value, Is.EqualTo(30));
source = new TypeSource { Value = 15 };
dest = translator.Translate(source, multiplier);
Assert.That(dest.Value, Is.EqualTo(45));
}
private class TypeTranslator
{
static TypeTranslator()
{
Mapper.CreateMap<TypeSource, TypeDest>()
.ConvertUsing<TypeConverter>();
}
public TypeDest Translate(TypeSource source, int multiplier)
{
return Mapper.Map<TypeDest>(source, opt => opt.Items.Add("multiplier", multiplier));
}
private class TypeConverter : ITypeConverter<TypeSource, TypeDest>
{
public TypeDest Convert(ResolutionContext context)
{
TypeSource source = (TypeSource)context.SourceValue;
int multiplier = (int)context.Options.Items["multiplier"];
return new TypeDest { Value = source.Value * multiplier };
}
}
}
private class TypeSource { public int Value { get; set; } }
private class TypeDest { public int Value { get; set; } }
Answering myself: I was not using AutoMapper.Reset(). Once I did that everything started working properly.
Helpful reading: http://www.markhneedham.com/blog/2010/01/27/automapper-dont-forget-mapper-reset-at-the-start/

How to verify Google Play Services

Im trying to figure that out for a few days now, but i can't find some good example about the problem. I think i have founded good code example, but i dont know where/how to use it.
About the problem: whenever app comes from foreground i would like to check if the Google play services are avalable. So for that i want use this code:
static final int REQUEST_CODE_RECOVER_PLAY_SERVICES = 1001;
private boolean checkPlayServices() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (status != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(status)) {
showErrorDialog(status);
} else {
Toast.makeText(this, "This device is not supported.",Toast.LENGTH_LONG).show();
finish();
}
return false;
}
return true;
}
void showErrorDialog(int code) {
GooglePlayServicesUtil.getErrorDialog(code, this,REQUEST_CODE_RECOVER_PLAY_SERVICES).show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_RECOVER_PLAY_SERVICES:
if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Google Play Services must be installed.",Toast.LENGTH_SHORT).show();
finish();
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
now i would like to check the services with
if (checkPlayServices()) {
System.out.println("ok");
}
but where? I have tryed to use that code in class that extends the game, but then
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
path cant be found. On the other hand, when i place it in separate activity
public class AuthActivity extends Activity {
//all previous code
}
path is ok. Does someone have any idea how to work that out?
Answer: Because this is Android-specific code, you must use that code in the Android module (containing the Activity class), not in the Core module (containing the class that extends Game).
Reason: If you put that function in the Core module, there is no library dependency of GooglePlayServicesUtil for the Core module, hence you cannot refer to the class GooglePlayServicesUtil. Read more on this link for using Android-specific code.

mvvmcross and authentication

Is there a way to authenticate a user through Facebook in mvvmcross framework? I'm currently attempting use Mobile Azure Service to authenticate to Facebook, but I don't have any success. Without using mvvmcross, I can authenticate just fine.
Thank You!
Mark
In the MVVM sense what I've found is that no, you can not. Properties on the facebook login page are not bindable, nor should they be and is best treated as a modal view out of your control
What I would do is make it a view concern and use Xamarin.Auth to authenticate.
As an example let's say that you had a LoginView and LoginViewModel.
The LoginView provides your standard login Email/Password but with an option (button) to authenticate via facebook
From that view hook up to the touchupinside event of the facebooklogin button
this.btnFacebookLogin.TouchUpInside += (object sender, EventArgs e) =>
{
DoFacebookLogin ();
}
Then in your DoFacebookLogin method 'present' the viewcontroller for facebook as described here https://github.com/xamarin/Xamarin.Auth/blob/master/GettingStarted.md
For example :
private void DoFacebookLogin ()
{
var auth = new OAuth2Authenticator (
clientId: "yournumericclientidhere",
scope: "",
authorizeUrl: new Uri ("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri ("http://www.facebook.com/connect/login_success.html"));
auth.AllowCancel = true;
auth.Completed += (sender, eventArgs) => {
DismissViewController (false, null);
if (eventArgs.IsAuthenticated) {
string user = eventArgs.Account.Serialize ();
var messenger = Mvx.Resolve<IMvxMessenger> ();
messenger.Publish (new FacebookLoggedIn (user));
} else {
// Cancelled here
}
};
var vc = auth.GetUI ();
this.PresentViewController (vc, true, null);
}
Cancelled does not need to be handled since the modal viewcontroller will take you back to your LoginView
On success that viewcontroller is dismissed then I would use mvx's interpretation of an eventaggregator (plugins.messenger) to send a message to the viewmodel that the facebook modal view is closed, with that message you can pass the account details - accesstoken etc back to the viewmodel to do as you wish.
View (as above) :
string user = eventArgs.Account.Serialize();
var messenger = Mvx.Resolve<IMvxMessenger> ();
messenger.Publish (new FacebookLoggedIn (user));
Message Class in your PCL :
public class FacebookLoggedIn : MvxMessage
{
public FacebookLoggedIn(object sender) : base(sender) {}
}
ViewModel also in your PCL :
public LoginViewModel()
{
var messenger = Mvx.Resolve<IMvxMessenger> ();
user = messenger.SubscribeOnMainThread<FacebookLoggedIn> (OnFacebookLoggedIn);
}
private void OnFacebookLoggedIn (FacebookLoggedIn MvxMessage)
{
... do something with the accesstoken? call your IUserService etc
ShowViewModel<MainViewModel> ();
}
Since you're dismissing the facebook viewcontroller you'll find yourself back on the loginview momentarily before automatically navigating to the MainView
In your view project you need to ensure the plugin is loaded otherwise you'll receive an error during construction of the viewmodel, so in setup.cs
protected override void InitializeLastChance ()
{
Cirrious.MvvmCross.Plugins.Messenger.PluginLoader.Instance.EnsureLoaded();
base.InitializeLastChance ();
}
Additionally you can also store the account credentials locally, this is described on the Xamarin.Auth link under AccountStore.Create().Save. Note that if you receive a platform not supported exception then add PLATFORM_IOS as a preprocessor directive to your project.
I realise the question is a couple of months old but since it rates high on google thought I'd provide an answer since there isn't any

Jade Agent Containers

Can anyone tell me how to find available agent containers through java code? I am using the JADE agent framework and I have figured out how to create new containers but not find existing containers (so that agents can be deployed in them).
There are two ways of doing this, depending on whether you want to receive the information via an ongoing service or the current snapshot in a message.
To get a snapshot of the IDs of the currently available agent containers, send a Request message to the Agent Management Service (AMS) and wait for its reply. Using the JADE Management Ontology and the QueryPlatformLocationsAction term, the sending and receiving methods would be:
private void queryAMS() throws CodecException, OntologyException {
QueryPlatformLocationsAction query = new QueryPlatformLocationsAction();
Action action = new Action(myAgent.getAID(), query);
ACLMessage message = new ACLMessage(ACLMessage.REQUEST);
message.addReceiver(myAgent.getAMS());
message.setLanguage(FIPANames.ContentLanguage.FIPA_SL);
message.setOntology(JADEManagementOntology.getInstance().getName());
myAgent.getContentManager().fillContent(message, action);
myAgent.send(message);
}
private void listenForAMSReply() throws UngroundedException, CodecException,
OntologyException {
ACLMessage receivedMessage = myAgent.blockingReceive(MessageTemplate
.MatchSender(myAgent.getAMS()));
ContentElement content = myAgent.getContentManager().extractContent(
receivedMessage);
// received message is a Result object, whose Value field is a List of
// ContainerIDs
Result result = (Result) content;
List listOfPlatforms = (List) result.getValue();
// use it
Iterator iter = listOfPlatforms.iterator();
while (iter.hasNext()) {
ContainerID next = (ContainerID) iter.next();
System.out.println(next.getID());
}
}
To get this information as an ongoing service, and to receive the ContainerID of each container as it registers with the AMS, create a Behaviour that extends the AMSSubscriber. Register a handler for the AddedContainer event and you will be able to access the ContainerID of the newly available container:
public class AMSListenerBehaviour extends AMSSubscriber {
#Override
public void installHandlers(Map handlersTable) {
handlersTable.put(AddedContainer.NAME, addedContainerHandler);
}
public final class AddedContainerHandler implements EventHandler {
#Override
public void handle(Event ev) {
AddedContainer event = (AddedContainer) ev;
ContainerID addedContainer = event.getContainer();
System.out.println(addedContainer.getID());
}
Hope this helps,
Russ