I've recently run into a snag while putting on the finishing touches for my BlackBerry app. I'm building a login screen which, if the user is successful in logging in, goes to a data loading screen, and then to a home screen. From the home screen, you can use the app. Everything works great but one thing, I can't seamlessly move from the login screen to the loading screen, to the home screen. I can move from the login screen to the loading screen ok, because I'm doing that via a button click which is on the GUI thread, but then I have the login screen at the bottom of the stack and can't get it out using the dismiss method. Once in the loading screen, I can't push the home screen because I'm not doing it via the gui method, though I'm able to update the GUI via the following piece of code:
private void checkData(){
Timer loadingTimer = new Timer();
TimerTask loadingTask = new TimerTask()
{
public void run()
{
// set the progress bar
progressGaugeField.setValue(DataManager.getDataLoaded());
// for repainting the screen
invalidate();
}
};
loadingTimer.scheduleAtFixedRate(loadingTask, 500, 500);
}
Does anyone know how to solve my problem of moving seamlessly from the login screen to the loading screen to the home screen? Note: once I'm at the home screen I'd like to have it be the only screen on the stack.
Thanks!
In this case, you may want to push the home screen of your application first and then push the login screen after it. I am not sure of your situation, but here are the assumptions I am making:
you are storing login information
if login information is not stored, you push the login screen
in a success case, you store login information and proceed to show the home screen
if login fails or is canceled, you don't display the home screen
If these assumptions are reasonably valid, the below code should work nicely for you.
public class YourApp extends UiApplication {
public YourApp() {
final AppHomeScreen screen = new AppHomeScreen();
pushScreen(screen);
if(getLoginInfo() == null) {
final LoginScreen loginScreen = new LoginScreen();
this.invokeLater(new Runnable() {
public void run() {
pushModalScreen(loginScreen);
if(getLoginInfo()==null)
popScreen(screen); //exit the app
}
//perhaps the loading screen populates info in your home screen then pops itself
pushScreen(new LoadingScreen(screen));
}
);
}
}
Have you tried putting the main screen on the stack first (from the Application) and, if no login has been attempted yet, push the login screen? In turn the login screen can push the loading screen. Once loading is completed, pop it out of the stack (from login) and close() login. You will then be back on the main screen with a logged in user.
For the loading to work and track its progress, you can use the following code
LoadingScreen lScreen = new LoadingScreen();
getUiEngine().pushScreen(lScreen);
_invokeIDGame = getApplication().invokeLater(new Runnable() {
public void run() {
// Check to see if the loading is done.
// implement an isLoading function to determine it
if (lScreen.isLoading() == false) {
// Cancel invoking this piece of code again (normally is invoked
// every 500 ms, as specified below)
getApplication().cancelInvokeLater(_invokeIDGame);
// Pop the loading screen off the stack, which returns the user to this screen
getUiEngine().popScreen(lScreen);
// close this screen
close();
}
}
}, 500, true); // rerun this code every 500ms
If you know in code when you need to push the screen, you can use the UiApplication pushScreen function. You start by getting a handle to the current application that has the UI:
UiApplication currentapp = UiApplication.getUiApplication();
You can compare the active screen in order to verify it's your application:
currentapp.getActiveScreen();
Then you can use the UiApplication instance to push your new screen:
currentapp.pushScreen(homeScreen);
I hope that helps :)
Related
I would like to create a nightly snapshot of certain tables in my SAAS-hosted Acumatica instance and SFTP the resulting XML file to a given location. (I've created a custom Export Mode option for just the tables of interest.)
I would like to do this process through an Acumatica Automation Schedule, a custom Action that I can call through the API, or an API call to existing Acumatica Actions, or some combination of the above.
However, it doesn't appear that these options are available to me:
Automation Scheduling doesn't support snapshot creation (https://feedback.acumatica.com/ideas/ACU-I-570)
I tried adding the Action to create a snapshot to the web service endpoint, but it doesn't appear that I can pass the parameters I would need to manage the pop-ups
Attempting to create a custom Acumatica button, I'm also to struggling to figure out how to raise and manage the pop-ups.
Once I have the snapshot created, I presume I will need to be able to download it locally in order to SFTP it to my desired location; I haven't gotten far enough to know if I invoke the download snapshot button through the API where the resulting file will go.
June,
When I get stuck with stuff that I am unable to trigger with ReST or other integration techniques I generally turn to Selenium as the path of least resistance. I do want to point out I always err on the side of using selenium as a last resort.
I generally like to use the PowerShell selenium module for stuff like this.
Once you have your script working you can wire it into a standard Windows Scheduler real easy.
It may not be the most elegant way to do it but it will certainly get the job done.
if your interested you can get started with this
https://github.com/adamdriscoll/selenium-powershell/blob/master/README.md
Once you get familiar with it you use the chrome inspection tool to dig into the elements that you need to target. the dialog boxes you are after are often found as iframes within the page.
I can share some of my scripts to help you get started if you want to try this route.
I hope this helps.
Robert
I ended up creating a simple console application since it was more in line with our other applications and I have more familiarity with C# than with PowerShell. Robert, your project was invaluable to figuring out how to reference the trickier elements.
I expect to set up scheduled tasks that will call my application with the method name of each step, with appropriate delays between each -- creating the snapshot takes about 25 minutes, for example. There are separate methods to create the snapshot, download the snapshot, delete the snapshot, and next I'm working on SFTPing the downloaded snapshot to its end destination. I put in sleeps to allow time for the website to catch up; there are Waits and WaitForExpectedCondition methods available but I didn't get into them in this quick and dirty version.
Here's the guts of my code. (I added WebDriver and ChromeDriver to the application via Nuget.)
using System;
using System.Collections.Generic;
using System.Linq;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System.Threading;
namespace InfiniteExport
{
class Program
{
static string connectorInfo;
static void Main(string[] args)
{
string method = "";
if (args.Count() >= 1)
{
method = args[0].ToLower();
}
IWebDriver driver = new ChromeDriver();
try
{
switch (method)
{
case "createsnapshot":
Login(driver);
CreateSnapshot(driver);
break;
case "downloadsnapshot":
Login(driver);
DownloadSnapshot(driver);
break;
case "deletesnapshot":
Login(driver);
DeleteSnapshot(driver);
break;
default:
break;
}
}
catch (Exception e)
{
throw e;
}
finally
{
driver.Quit();
}
}
static void Login(IWebDriver driver)
{
//This login actually results in a 404 error because there's no redirect embedded in it, but the login itself is successful and creates the session used by the next method navigation
driver.Navigate().GoToUrl(InfiniteExport.Properties.Settings.Default.BaseAcumaticaURL + "/Frames/Login.aspx");
driver.FindElement(By.Id("form1")).Click();
driver.FindElement(By.Id("txtUser")).SendKeys(InfiniteExport.Properties.Settings.Default.AcumaticaUserName);
driver.FindElement(By.Id("txtPass")).SendKeys(InfiniteExport.Properties.Settings.Default.AcumaticaPassword);
driver.FindElement(By.Id("btnLogin")).Click();
driver.Manage().Window.Maximize();
Thread.Sleep(5000);
}
static void CreateSnapshot(IWebDriver driver)
{
driver.Navigate().GoToUrl(#InfiniteExport.Properties.Settings.Default.BaseAcumaticaURL + "/Main?ScreenId=SM203520&_CompanyID=2");
Thread.Sleep(2000);
driver.SwitchTo().Frame("main");
//Click the #$##%*! unnamed create snapshot button
driver.FindElement(By.CssSelector(".toolsBtn[data-cmd=exportSnapshotCommand]")).Click();
Thread.Sleep(2000);
//Switch to the modal popup to start clicking items on it (this is the "Warning not in maintenance mode" popup)
driver.SwitchTo().ActiveElement();
driver.FindElement(By.Id("messageBox_0")).Click();
Thread.Sleep(2000);
//Switch to the modal popup with the export options
driver.SwitchTo().ActiveElement();
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_edDescription")).SendKeys("InfiniteExport");
//Select the dropdown option for the InfiniteExport
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_edExportMode_text")).Click();
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_edExportMode_text")).SendKeys("InfiniteExport");
Thread.Sleep(2000);
driver.FindElement(By.ClassName("ddSelection")).Click();
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_chkPrepare")).Click();
//Select the dropdown option for XML
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_edPrepareMode")).Click();
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_frmExportSnapshot_edPrepareMode_text")).SendKeys("XML");
Thread.Sleep(2000);
driver.FindElement(By.ClassName("ddSelection")).Click();
Thread.Sleep(2000);
//Click the OK button to start the export
driver.FindElement(By.Id("ctl00_phF_pnlExportSnapshot_btnExportSnapshotOK")).Click();
//Wait long enough for the process to start, then quit and come back later to download
Thread.Sleep(10000);
}
static void DownloadSnapshot(IWebDriver driver)
{
driver.Navigate().GoToUrl(#InfiniteExport.Properties.Settings.Default.BaseAcumaticaURL + "/Main?ScreenId=SM203520&_CompanyID=2");
Thread.Sleep(2000);
driver.SwitchTo().Frame("main");
//Unless this is made fancier, it will download the active grid row, which is the most recent snapshot created
driver.FindElement(By.CssSelector(".toolsBtn[data-cmd=downloadSnapshotCommand]")).Click();
Thread.Sleep(10000);
}
static void DeleteSnapshot(IWebDriver driver)
{
driver.Navigate().GoToUrl(#InfiniteExport.Properties.Settings.Default.BaseAcumaticaURL + "/Main?ScreenId=SM203520&_CompanyID=2");
Thread.Sleep(2000);
driver.SwitchTo().Frame("main");
//Unless this is made fancier, it will delete the active grid row, which is the most recent snapshot created
driver.FindElement(By.CssSelector(".toolsBtn[data-cmd=Delete]")).Click();
Thread.Sleep(2000);
driver.FindElement(By.CssSelector(".toolsBtn[data-cmd=saveCompanyCommand]")).Click();
Thread.Sleep(10000);
}
}
}
I want to prevent the phone to lock if the user didnt interact with the phone for some time.
In win8 phone development i used the PhoneApplicationService.UserIdleDetectionMode Property. Unfortunately i cannot find anything alike for win 10 universal app.
Any suggestions?
Simple Answer
DisplayRequest class
var displayRequest = new DisplayRequest();
displayRequest.RequestActive(); //to request keep display on
displayRequest.RequestRelease(); //to release request of keep display on
Detailed Answer
Using display requests to keep the display on consumes a lot of power. Use these guidelines for best app behavior when using display requests.
Use display requests only when required, that is, times when no user input is expected but the display should remain on. For example, during full screen presentations or when the user is reading an e-book.
Release each display request as soon as it is no longer required.
Release all display requests when the app is suspended. If the display is still required to remain on, the app can create a new display request when it is reactivated.
To Request keep display on
private void Activate_Click(object sender, RoutedEventArgs e)
{
if (g_DisplayRequest == null)
{
g_DisplayRequest = new DisplayRequest();
}
if (g_DisplayRequest != null)
{
// This call activates a display-required request. If successful,
// the screen is guaranteed not to turn off automatically due to user inactivity.
g_DisplayRequest.RequestActive();
drCount += 1;
}
}
To release request of keep display on
private void Release_Click(object sender, RoutedEventArgs e)
{
// This call de-activates the display-required request. If successful, the screen
// might be turned off automatically due to a user inactivity, depending on the
// power policy settings of the system. The requestRelease method throws an exception
// if it is called before a successful requestActive call on this object.
if (g_DisplayRequest != null)
{
g_DisplayRequest.RequestRelease();
drCount -= 1;
}
}
References - Prevent the screen from locking on Universal Windows Platform
Hope it help someone!!
You want the DisplayRequest class in Windows 10.
i`m using mediaElement to play background music in my app. And that works just fine.
Problem is when the user minimize the application. When the application resume there is no sound... I can play other sounds in my application but cant play that background music any more.
First i have this code to stop all background music at first time app open:
if (Microsoft.Xna.Framework.Media.MediaPlayer.State == MediaState.Playing)
{
Microsoft.Xna.Framework.Media.MediaPlayer.Pause();
FrameworkDispatcher.Update();
}
xaml code of that mediaElement
<MediaElement AutoPlay="True" Source="/Dodaci/pozadina.mp3" x:Name="muzika_pozadina" MediaEnded="pustiPonovo" Loaded="pustiPonovo" />
and the cs code
private void pustiPonovo(object sender, RoutedEventArgs e)
{
muzika_pozadina.Play();
}
sound is about 300kb size.
So, how can i resume that sound playing after the user resume the application?
When your App is put into Dormant State (when you hit Start buton for example), the MediaElement is stopped. Then after you return to your App (and it wasn't Tombstoned), the Page is not Initialized once again, which means that your MediaElement is not loaded once again, so your Music doesn't start once again.
It depends on your purpose and code how it can be returned. In very simple example when you don't need to remember music last position you can just set source of your MediaElement once again in OnNavigatedTo() event:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode == NavigationMode.Back)
muzika_pozadina.Source = new Uri("/Dodaci/pozadina.mp3", UriKind.RelativeOrAbsolute);
}
As you have set your MediaElement.AutoPlay to true - it should start automatically (because of that you probably also don't need your Loaded event pustiPonovo).
In more complicated cases you can take an advantage of Activation and Deactivation events of your App - returning to MediaElement from Dormant/Tombstoned case is well explained here in the article.
You should also read about Fast App Resume in case User decides to return to your App by Tile instead of Launchers-Choosers.
I haven't tried above code, but hopefully it will do the job.
1) I click the start connect button in my client program. I successfully set the start button backcolor to red.
2) When the TCP connection is completed, a registration message is sent and it successfully changes the button backcolor to yellow.
3) The server sends a registration ACK back to the client and that is processed in a backgroundworker (BGW). BGW sets a boolean variable SetConnectButton so that it is known registration was successful, then completes.
4) The RunWorkerCompleted function is ran. The debug window displays "Lime" as it should, but the button color does not change. Here is the RunWorkerCompleted code.
static private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (SetConnectButton)
{
Debug.WriteLine("Lime");
SetConnectButton = false;
UIMain.btnServerConnect.BackColor = System.Drawing.Color.Lime;
}
}//close WorkerCompleted
As I understand it, the RunWorkerCompleted runs in the UI thread so this should work as is. Using Invoke made no difference, though I may not have done it right.
Any clues?
Problem solved by using Context.Post method when calling the function that writes the UI.
I am trying to set up a background service that would perform bulk loading of transaction data from a csv file. This background service would be initiated from a menu item action mapped to a method in the controller/presenter class.
Ever so often, some data turns up in the csv file for which no master data can be found in the database, this would normally cause the upload to choke and fail.
On such occasions, I would like to be able to have the background service pause its processing and invoke a dialog from a presenter class to take in user input. The user input would be used to add a master row in the database, after which the background service should resume from where it had left off (not from the beginning of the csv file, but from the row which caused the error).
Is this possible to achieve in JavaFX, perhaps with the javafx.concurrent API? How would I go about doing this?
Solution
When your background process encounters a situation where it requires a user to be prompted for input, use FutureTask executed in Platform.runLater to showAndWait the dialog prompt on the JavaFX application thread. In the background process use futureTask.get to pause the background process until the user has input the necessary values which will allow the process to continue.
Sample Code Snippet
Here is the essence of code for this approach which can be placed inside the call method of your background process:
String nextText = readLineFromSource();
if ("MISSING".equals(nextText)) {
updateMessage("Prompting for missing text");
FutureTask<String> futureTask = new FutureTask(
new MissingTextPrompt()
);
Platform.runLater(futureTask);
nextText = futureTask.get();
}
...
class MissingTextPrompt implements Callable<String> {
private TextField textField;
#Override public String call() throws Exception {
final Stage dialog = new Stage();
dialog.setScene(createDialogScene());
dialog.showAndWait();
return textField.getText();
}
...
}
Sample Application
I created a small, complete sample application to demonstrate this approach.
The output of the sample application is:
Sample Output Explanation
Lines read without missing values are just plain brown.
Lines with a prompt value entered have a pale green background.
Fourteen lines have been read, the background task has already paused once at the 6th line which was missing a value. The user was prompted for the missing value (to which the user entered xyzzy), then the process continued until line 14 which is also missing and the background task is again paused and another prompt dialog is being displayed.