Remove repetitive fragments from fragment manager in Xamarin Android - xamarin

I am working on android using Xamarin and MVVMCross framework. I want to update the remove the fragment from fragment manager to handle the back button, Because i have to navigate between screen which make a cross reference in Back Stack. So i want to remove the repetitive entries from stack. Its removing the repetitive entries from stack but it does not update the BackStackEntryCount with latest fragments.
I have written code
public override void OnFragmentChanged(IMvxCachedFragmentInfo fragmentInfo)
{
if (fragmentInfo != null)
{
var ifExists =
SupportFragmentManager.Fragments?.FirstOrDefault(x => x.Tag.ToLower() == fragmentInfo.Tag.ToLower());
if (ifExists != null)
{
var indexOf = SupportFragmentManager.Fragments.IndexOf(ifExists);
var total = SupportFragmentManager.BackStackEntryCount;
for (int i = indexOf + 1; i < total; i++)
{
SupportFragmentManager.Fragments.RemoveAt(i);
}
}
}
base.OnFragmentChanged(fragmentInfo);
}

SupportFragmentManager.Fragments is a read only property (It only has a get). Modifying the content of the list of fragment has no impact on the underline fragment backstack count.
What you can instead try is to pop the stack down to the existing fragment. This should remove all fragments above it.
var exisitngFragment = SupportFragmentManager.FindFragmentByTag(fragmentInfo.Tag);
SupportFragmentManager.PopBackStackImmediate(exisitngFragment.Id, 0);

Related

UWP: calculate expected size of screenshot using multiple monitor setup

Right, parsing the clipboard, I am trying to detect if a stored bitmap in there might be the result of a screenshot the user took.
Everything is working fine as long as the user only has one monitor. Things become a bit more involved with two or more.
I am using the routing below to grab all the displays in use. Now, since I have no idea how they are configured to hang together, I do not know how to calculate the size of the screenshot (that Windows would produce) from that information.
I explicitly do not want to take a screenshot myself to compare. It's a privacy promise by my app.
Any ideas?
Here is the code for the size extractor, run in the UI thread.
public static async Task<Windows.Graphics.SizeInt32[]> GetMonitorSizesAsync()
{
Windows.Graphics.SizeInt32[] result = null;
var selector = DisplayMonitor.GetDeviceSelector();
var devices = await DeviceInformation.FindAllAsync(selector);
if (devices?.Count > 0)
{
result = new Windows.Graphics.SizeInt32[devices.Count];
int i = 0;
foreach (var device in devices)
{
var monitor = await DisplayMonitor.FromInterfaceIdAsync(device.Id);
result[i++] = monitor.NativeResolutionInRawPixels;
}
}
return result;
}
Base on Raymonds comment, here is my current solution in release code...
IN_UI_THREAD is a convenience property to see if the code executes in the UI thread,
public static Windows.Foundation.Size GetDesktopSize()
{
Int32 desktopWidth = 0;
Int32 desktopHeight = 0;
if (IN_UI_THREAD)
{
var regions = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView()?.WindowingEnvironment?.GetDisplayRegions()?.Where(r => r.IsVisible);
if (regions?.Count() > 0)
{
// Get grab the most left and the most right point.
var MostLeft = regions.Min(r => r.WorkAreaOffset.X);
var MostTop = regions.Min(r => r.WorkAreaOffset.Y);
// The width is the distance between the most left and the most right point
desktopWidth = (int)regions.Max(r => r.WorkAreaOffset.X + r.WorkAreaSize.Width - MostLeft);
// Same for height
desktopHeight = (int)regions.Max(r => r.WorkAreaOffset.Y + r.WorkAreaSize.Height - MostTop);
}
}
return new Windows.Foundation.Size(desktopWidth, desktopHeight);
}

Photoshop CC2019 auto-update all linked smart objects including nested ones

I have Photoshop CC2019 PSD document containing several smart objects that contains other smart objects that contains other smart objects. Some of these have linked layers. Normally, such images are not updated automatically (which is extremely annoying, Adobe!) but you have to manually update each of them once the linked image content has changed.
There is a .jsx script file named "Update All Modified Content.jsx" which auto-updates linked layers (PNG image in my case) but only if the smart object is in the top most document - that is no nested smart objects with linked layers are updated automatically.
My question is: does anyone know how to update the content of the above mentioned .jsx file so that it would auto-update all linked images across all the smart objects in PSD document including nested ones?
For those who care or would be willing to help updating the code here it is:
// Update all modified content
var idplacedLayerUpdateAllModified = stringIDToTypeID( "placedLayerUpdateAllModified" );
executeAction( idplacedLayerUpdateAllModified, undefined, DialogModes.NO );
So, after spending half a day with it I finally solved it myself. Here is the code:
#target photoshop
// SET INITIAL ACTIVE DOCUMENT
var mainDocument = app.activeDocument;
// SAVE THE DOCUMENT NAME FOR FUTURE USE
var mainDocName = mainDocument.name;
// RUN THE MAIN UPDATE FUNCTION
mainDocument.suspendHistory("processAllSmartObjects", "autoupdateAllSmartObjects(mainDocument, 0)");
// FINALLY SAVE THE MAIN DOCUMENT
mainDocument.save();
function autoupdateAllSmartObjects(theParent, prevVal) {
// FUNCTION TO TEST IF SMARTOBJECT IS LINKED
function isLinkedSO(obj) {
var localFilePath = "";
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), obj.id);
var desc = executeActionGet(ref);
var smObj = desc.getObjectValue(stringIDToTypeID('smartObject'));
var isLinked = false;
// TEST IF IT HAS LINKED FILE
try {
var localFilePath = smObj.getPath(stringIDToTypeID('link'));
isLinked = true;
} catch(e) {
//
}
return isLinked;
}
// FUNCTION TO UPDATE LINKED SMART OBJECT
function doTheUpdate(LYR, stackNr) {
// SET ACTIVE LAYER TO ACTUALY ITERATED ONE
app.activeDocument.activeLayer = LYR;
// RUN IN "SILENT" MODE
app.displayDialogs = DialogModes.NO;
var layer = app.activeDocument.activeLayer;
// IF ACTIVE LAYER IS SMARTOBJECT
if (layer.kind == "LayerKind.SMARTOBJECT") {
//alert(layer);
// OPEN THE SMARTOBJECT
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
// DO THE ACTUAL FILE UPDATE
var idplacedLayerUpdateAllModified = stringIDToTypeID( "placedLayerUpdateAllModified" );
executeAction( idplacedLayerUpdateAllModified, undefined, DialogModes.NO);
// IF IT IS NOT THE "CORE/MAIN" DOCUMENT
if(stackNr > 0) {
// SAVE CHANGES (UPDATE) AND CLOSE IT
app.activeDocument.close(SaveOptions.SAVECHANGES);
}
// CONTINUE INSIDE THIS ACTIVE SMARTOBJECT
autoupdateAllSmartObjects(app.activeDocument, stackNr);
}
return;
}
// FUNCTION TO PARSE GROUPS
function parseGroup(LYR) {
var groupLayers = LYR.layers;
// IF GROUP IS NOT EMPTY
if(groupLayers.length > 0) {
// PARSE ALL LAYERS IN THE GROUP
for (var i = groupLayers.length - 1; i >= 0; i--) {
var lyr = groupLayers[i];
// IF NOT LOCKED = NOT EDITABL:E
if(!lyr.allLocked) {
// YET ANOTHER GROUP?
if (lyr.typename == "LayerSet") {
// IF IT IS NOT EMPTY
if (lyr.layers.length > 0) {
// RE-RUN THE SCRIPT ANEW WITH THE SELECTED GROUP AS LAYERS SOURCE
autoupdateAllSmartObjects(lyr, 0);
}
// LAYERS
} else if (lyr.typename == "ArtLayer") {
// IF THE LAYER IS SMARTOBJECT
if (lyr.kind == LayerKind.SMARTOBJECT) {
// IF THE LAYER IS SET TO "visible" (THAT IS: NOT DISABLED)
if(lyr.visible){
// TEST IF THE SMARTOBJECT IS ACTUALLY LINKED
if(!isLinkedSO(lyr)) {
// RUN THE UPDATE SUB-FUNCTION
doTheUpdate(lyr, i);
}
}
}
}
}
}
}
}
// PARSE ALL THE LAYERS
for (var i = theParent.layers.length - 1 - prevVal; i >= 0; i--) {
var theLayer = theParent.layers[i];
// ONLY ArtLayers
if (theLayer.typename == "ArtLayer") {
// IF THE LAYER IS SMARTOBJECT
if (theLayer.kind == LayerKind.SMARTOBJECT) {
// IF THE LAYER IS SET TO "visible" (THAT IS: NOT DISABLED)
if(theLayer.visible){
// TEST IF THE SMARTOBJECT IS ACTUALLY LINKED
if(!isLinkedSO(theLayer)){
// RUN THE UPDATE SUB-FUNCTION
doTheUpdate(theLayer, i);
// IF WE ARE AT THE LAST LAYER IN THE STACK AND IT IS NOT OUR MAIN DOCUMENT
if(i == 0 && app.activeDocument.name !== mainDocName) {
// SAVE CHANGES (UPDATE) AND CLOSE IT
app.activeDocument.close(SaveOptions.SAVECHANGES);
}
}
}
}
// ONLY Groups
} else if (theLayer.typename == "LayerSet") {
// RUN SUB-FUNCTION FOR GROUP PARSING
parseGroup(theLayer);
// ANYTHING ELSE
} else {
autoupdateAllSmartObjects(theLayer, m);
}
}
return;
};
OP's script works!! It was going in loops for me too but after some trial and error, I realised that my smart objects (SO) that are linked across artboards ( - e.g. if you change one SO, it changes on various artboards) - were the issue. I hid all such SO and it works.
so basically, it only works for Smart Objects + copies made via 'New smart object via copy' NOT 'duplicate layer' / copypaste smart objects. If your work contains a 'duplicate layer' SO - it will break the script. You need to hide these objects ( or not work like that all together) before running the script

CharmListView Infinite Scroll

I need basically an event that triggers at each 200 records loaded, so more data can be loaded until the end of data.
I tried to extend CharmListCell and using the method updateItem like this:
#Override
public void updateItem(Model item, boolean empty) {
super.updateItem(item, empty);
currentItem = item;
if (!empty && item != null) {
update();
setGraphic(slidingTile);
} else {
setGraphic(null);
}
System.out.println(getIndex());
}
But the System.out.println(getIndex()); method returns -1;
I would like to call my backend method when the scroll down gets the end of last fetched block and so on, until get the end of data like the "infinite scroll" technique.
Thanks!
The CharmListCell doesn't expose the index of the underlying listView, but even if it did, that wouldn't be of much help to find out if you are scrolling over the end of the current list or not.
I'd suggest a different approach, which is also valid for a regular ListView, with the advantage of having the CharmListView features (mainly headers and the refresh indicator).
This short sample, created with a single view project using the Gluon IDE plugin and Charm 5.0.0, shows how to create a CharmListView control, and fill it with 30 items at a time. I haven't provided a factory cell, nor the headers, and for the sake of simplicity I'm just adding consecutive integers.
With a lookup, and after the view is shown (so the listView is added to the scene) we find the vertical ScrollBar of the listView, and then we add a listener to track its position. When it gets closer to 1, we simulate the load of another batch of items, with a pause transition that represents a heavy task.
Note the use of the refresh indicator. When new data is added, we scroll back to the first of the new items, so we can keep scrolling again.
public class BasicView extends View {
private final ObservableList<Integer> data;
private CharmListView<Integer, Integer> listView;
private final int batchSize = 30;
private PauseTransition pause;
public BasicView() {
data = FXCollections.observableArrayList();
listView = new CharmListView<>(data);
setOnShown(e -> {
ScrollBar scrollBar = null;
for (Node bar : listView.lookupAll(".scroll-bar")) {
if (bar instanceof ScrollBar && ((ScrollBar) bar).getOrientation().equals(Orientation.VERTICAL)) {
scrollBar = (ScrollBar) bar;
break;
}
}
if (scrollBar != null) {
scrollBar.valueProperty().addListener((obs, ov, nv) -> {
if (nv.doubleValue() > 0.95) {
addBatch();
}
});
addBatch();
}
});
setCenter(new VBox(listView));
}
private void addBatch() {
listView.setRefreshIndicatorVisible(true);
if (pause == null) {
pause = new PauseTransition(Duration.seconds(1));
pause.setOnFinished(f -> {
int size = data.size();
List<Integer> list = new ArrayList<>();
for (int i = size; i < size + batchSize; i++) {
list.add(i);
}
data.addAll(list);
listView.scrollTo(list.get(0));
listView.setRefreshIndicatorVisible(false);
});
} else {
pause.stop();
}
pause.playFromStart();
}
}
Note also that you could benefit from the setOnPullToRefresh() method, at any time. For instance, if you add this:
listView.setOnPullToRefresh(e -> addBatch());
whenever you go to the top of the list and drag it down (on a mobile device), it will make another call to load a new batch of items. Obviously, this is the opposite behavior as the "infinite scrolling", but it is possible as well with the CharmListView control.

How can I replace an image in Google Documents?

I'm trying to insert images into Google Docs (other GSuite apps later) from an Add-On. I've succeeded in fetching the image and inserting it when getCursor() returns a valid Position. When there is a selection (instead of a Cursor), I can succeed if it's text that's selected by walking up to the Parent of the selected text and inserting the image at the start of the paragraph (not perfect, but OK).
UPDATE: It seems that I was using a deprecated method (getSelectedElements()), but that didn't fix the issue. It seems the issue is only with wrapped images as well (I didn't realize that the type of the object changed when you changed it to a wrapped text).
However, when an wrapped-text Image (presumably a PositionedImage) is highlighted (with the rotate and resize handles visible in blue), both getSelection() and getCursor() return null. This is a problem as I would like to be able to get that image and replace it with the one I'm inserting.
Here's my code... any help would be great.
var response = UrlFetchApp.fetch(imageTokenURL);
var selection = DocumentApp.getActiveDocument().getSelection();
if (selection)
{
Logger.log("Got Selection");
var replaced = false;
var elements = selection.getRangeElements();
if (elements.length === 1
&& elements[0].getElement().getType() === DocumentApp.ElementType.INLINE_IMAGE)
{
//replace the URL -- this never happens
}
//otherwise, we take the first element and work from there:
var firstElem = elements[0].getElement();
Logger.log("First Element Type = " + firstElem.getType());
if (firstElem.getType() == DocumentApp.ElementType.PARAGRAPH)
{
var newImage = firstElem.asParagraph().insertInlineImage(0, response);
newImage.setHeight(200);
newImage.setWidth(200);
}
else if (firstElem.getType() == DocumentApp.ElementType.TEXT)
{
var p = firstElem.getParent();
if (p.getType() == DocumentApp.ElementType.PARAGRAPH)
{
var index = p.asParagraph().getChildIndex(firstElem);
var newImage = p.asParagraph().insertInlineImage(index, response);
newImage.setHeight(200);
newImage.setWidth(200);
}
}
} else {
Logger.log("Checking Cursor");
var cursor = DocumentApp.getActiveDocument().getCursor();
if (cursor)
{
Logger.log("Got Cursor: " + cursor);
var newImage = cursor.insertInlineImage(response);
var p = cursor.getElement();
var size=200;
newImage.setHeight(size);
newImage.setWidth(size);
}
}
You are using the deprecated 'getSelectedElements()' method of the Range class. You may notice it's crossed out in the autocomplete selection box.
Instead, use the 'getRangeElements()' method. After selecting the image in the doc, the code below worked for me:
var range = doc.getSelection();
var element = range.getRangeElements()[0].getElement();
Logger.log(element.getType() == DocumentApp.ElementType.INLINE_IMAGE); //logs 'true'

Loop through all buttons on screen for a given tag, WP7, using C#

I'm looking for a simple way to loop through all buttons onscreen for a given tag. Eg "foo". I'm using WP7, using C#. I'm very new to the platform so go easy on me :P
Googling this sort of thing isn't really working out for me either - I think I have my terminology wrong, so any tips on that too would be appreciated.
You should probably loop through all the controls on your page, check whether each one is a button, and if so check its Tag property.
Something like this...
foreach (UIElement ctrl in ContentPanel.Children)
{
if (ctrl.GetType() == typeof(Button))
{
Button potentialButton = ((Button)ctrl);
if (potentialButton.Tag = Tag)
return (Button)ctrl;
}
}
Bear in mind, though, that if you have nested controls on the page, you will need to think about recursing into any item with children to make sure you catch all the controls.
First, create a method to enumerate recursively the controls in your page:
public static IEnumerable<FrameworkElement> FindVisualChildren(FrameworkElement control)
{
if (control == null)
{
yield break;
}
for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(control); i++)
{
var child = System.Windows.Media.VisualTreeHelper.GetChild(control, i) as FrameworkElement;
if (child != null)
{
yield return child;
foreach (var grandChild in FindVisualChildren(child))
{
yield return grandChild;
}
}
}
}
Then call it and keep only the controls you want:
var buttons = FindVisualChildren(this.ContentPanel)
.OfType<Button>()
.Where(b => b.Tag is string && (string)b.Tag == "foo");
(where ContentPanel is the root element of your page)

Resources