I am very new at making apps, this being my 3rd week, and I'm not sure the syntax needed to make my idea work.
When the first button is clicked I want it to save the class that is the destination (in this case OddesyYears but could be any random class) to be saved/remembered before going to the intent.
Button button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("key", "OddesyYears");
editor.commit();
Intent i = new Intent(getBaseContext(),OddesyYears.class);
startActivity(i);
Then at a later time after app has been closed/turned off and reopened...
public void onClick(View v) {
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
String MyCar = sharedPreferences.getString("key", "RandomClass");
If (MyCar == null)
Toast.makeText(getBaseContext(),
"Please Select from other window",
Toast.LENGTH_SHORT).show();
elseIf()
Intent i = new Intent(getBaseContext(),MyCar.class);
startActivity(i);
The class will be remembered and accessed from another button for the life of the app. This will remain empty until something is saved then access the saved location when the user wants. I'm trying to pass it as a string which is failing miserably and not sure where else to turn. Maybe intent.shortcut?
I also want this to remain fairly generic since the user can choose to access many different classes and each time one is chosen it will write over the old one.
Much thanks!
Related
I have 2 dropdowns (pickers) on a XAML form. The first is an ObservabelCollection of Territories. The second is an ObservableCollection of type Tracks. When the form loads my ViewModel loads both collections and each collection is bound to a picker. I want to filter and display only those tracks that are associated with the selected territory in the second picker.
FYI-the second picker is disabled until a selection is made in the first. Actually I don't require that the second picker's data source be set as the form loads, unless the solution requires it. The selection in the first picker will be the key to filter the data for the second.
I have tried to handle the filtering in the Territory picker's SelectedIndexChanged event but my ObservableCollection 'tracks' is not exposed here.
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
Tracks _track = tracks.Where(X => X.Territory = territory);<<<==== Does not work
trackPicker.ItemsSource = _track.Track;<<<==== Does not work
trackPicker.IsEnabled = true;
}
I've also tried to not build the Tracks OC until after the Territory is selected like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
TrackViewModel vm = new TrackViewModel();
var _tracks = (Tracks)vm.Tracks; <<<<<==== This does not work
trackPicker.IsEnabled = true;
}
The ViewModel runs and the tracks are loaded via the API but when it returns here Tracks is empty.
I'm open to a reasonable solution (not 3rd party controls/packages) that will accomplish this task . Thanks
I figured it out by stumbling over the answer while researching another issue. I have been referencing my viewmodel in the {content].xaml page like this.
<ContentPage.BindingContext>
<vm:TrackViewModel />
</ContentPage.BindingContext>
When doing so the resources of that vm were not available in the code behind. But when I reference the VM in the page constructor Like this:
public partial class RequestmyTracks : ContentPage
{
TrackViewModel trackviewmodel = new TrackViewModel();
And then bind it here:
public RequestmyTracks()
{
InitializeComponent();
BindingContext = trackviewmodel;
}
The trackviewmodel is accessible in the SelectedIndexChanged event and everything else was really straight forward, Which looks like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
ObservableCollection<Tracks> dah = (ObservableCollection<Tracks>)trackviewmodel.Tracks;
List<string> trackNames = new List<string>();
foreach (var track in dah)
{
if (track.Territory == territory)
trackNames.Add(track.Track);
}
trackPicker.ItemsSource = trackNames;
if(trackNames.Count ==1)
trackPicker.SelectedIndex = 0;
trackPicker.IsEnabled = true;
}
Thanks for the help
I'm using Paging Library to load data from network using ItemKeyedDataSource. After fetching items user can edit them, this updates are done inside in Memory cache (no database like Room is used).
Now since the PagedList itself cannot be updated (discussed here) I have to recreate PagedList and pass it to the PagedListAdapter.
The update itself is no problem but after updating the recyclerView with the new PagedList, the list jumps to the beginning of the list destroying previous scroll position. Is there anyway to update PagedList while keeping scroll position (like how it works with Room)?
DataSource is implemented this way:
public class MentionKeyedDataSource extends ItemKeyedDataSource<Long, Mention> {
private Repository repository;
...
private List<Mention> cachedItems;
public MentionKeyedDataSource(Repository repository, ..., List<Mention> cachedItems){
super();
this.repository = repository;
this.teamId = teamId;
this.inboxId = inboxId;
this.filter = filter;
this.cachedItems = new ArrayList<>(cachedItems);
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Long> params, final #NonNull ItemKeyedDataSource.LoadInitialCallback<Mention> callback) {
Observable.just(cachedItems)
.filter(() -> return cachedItems != null && !cachedItems.isEmpty())
.switchIfEmpty(repository.getItems(..., params.requestedLoadSize).map(...))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
#Override
public void loadAfter(#NonNull LoadParams<Long> params, final #NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getOlderItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
#Override
public void loadBefore(#NonNull LoadParams<Long> params, final #NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getNewerItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
#NonNull
#Override
public Long getKey(#NonNull Mention item) {
return item.id;
}
}
The PagedList created like this:
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(PAGE_SIZE)
.setInitialLoadSizeHint(preFetchedItems != null && !preFetchedItems.isEmpty()
? preFetchedItems.size()
: PAGE_SIZE * 2
).build();
pagedMentionsList = new PagedList.Builder<>(new MentionKeyedDataSource(mRepository, team.id, inbox.id, mCurrentFilter, preFetchedItems)
, config)
.setFetchExecutor(ApplicationThreadPool.getBackgroundThreadExecutor())
.setNotifyExecutor(ApplicationThreadPool.getUIThreadExecutor())
.build();
The PagedListAdapter is created like this:
public class ItemAdapter extends PagedListAdapter<Item, ItemAdapter.ItemHolder> { //Adapter from google guide, Nothing special here.. }
mAdapter = new ItemAdapter(new DiffUtil.ItemCallback<Mention>() {
#Override
public boolean areItemsTheSame(Item oldItem, Item newItem) {
return oldItem.id == newItem.id;
}
#Override
public boolean areContentsTheSame(Item oldItem, Item newItem) {
return oldItem.equals(newItem);
}
});
, and updated like this:
mAdapter.submitList(pagedList);
You should use a blocking call on your observable. If you don't submit the result in the same thread as loadInitial, loadAfter or loadBefore, what happens is that the adapter will compute the diff of the existing list items against an empty list first, and then against the newly loaded items. So effectively it's as if all items were deleted and then inserted again, that is why the list seems to jump to the beginning.
You're not using androidx.paging.ItemKeyedDataSource.LoadInitialParams#requestedInitialKey in your implementation of loadInitial, and I think you should be.
I took a look at another implementation of ItemKeyedDataSource, the one used by autogenerated Room DAO code: LimitOffsetDataSource. Its implementation of loadInitial contains (Apache 2.0 licensed code follows):
// bound the size requested, based on known count
final int firstLoadPosition = computeInitialLoadPosition(params, totalCount);
final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
... where those functions do something with params.requestedStartPosition, params.requestedLoadSize and params.pageSize.
So what's going wrong?
Whenever you pass a new PagedList, you need to make sure that it contains the elements that the user is currently scrolled to. Otherwise, your PagedListAdapter will treat this as a removal of these elements. Then, later, when your loadAfter or loadBefore items load those elements, it will treat them as a subsequent insertion of these elements. You need to avoid doing this removal and insertion of any visible items. Since it sounds like you're scrolling to the top, maybe you're accidentally removing all items and inserting them all.
The way I think this works when using Room with PagedLists is:
The database is updated.
A Room observer invalidates the data source.
The PagedListAdapter code spots the invalidation and uses the factory to create a new data source, and calls loadInitial with the params.requestedStartPosition set to a visible element.
A new PagedList is provided to the PagedListAdapter, who runs the diff checking code to see what's actually changed. Usually, nothing has changed to what's visible, but maybe an element has been inserted, changed or removed. Everything outside the initial load is treated as being removed - this shouldn't be noticeable in the UI.
When scrolling, the PagedListAdapter code can spot that new items need to be loaded, and call loadBefore or loadAfter.
When these complete, an entire new PagedList is provided to the PagedListAdapter, who runs the diff checking code to see what's actually changed. Usually - just an insertion.
I'm not sure how that corresponds to what you're trying to do, but maybe that helps? Whenever you provide a new PagedList, it will be diffed against the previous one, and you want to make sure that there's no spurious insertions or deletions, or it can get really confused.
Other ideas
I've also seen issues where PAGE_SIZE is not big enough. The docs recommend several times the maximum number of elements that can be visible at a time.
This also happens when DiffUtil.ItemCallback is not correctly implemented. And by correct implementation I mean, you should properly check whether the oldItem and newItem are same or not and accordingly return true or false from areItemsTheSame() and areContentsTheSame() methods.
For example, if I always return false from both of these methods like:
DiffUtil.ItemCallback<Mention>() {
#Override
public boolean areItemsTheSame(Item oldItem, Item newItem) {
return false;
}
#Override
public boolean areContentsTheSame(Item oldItem, Item newItem) {
return false;
}
}
The library thinks that all the items are new therefore it jumps to the top to display all the new items.
So make sure you carefully check the oldItem and newItem and properly return true or false based on your comparisons
I've following code, this was copied from one of questions here on SOF,
private void showMyMessage() {
ApplicationManager.getApplication().invokeLater(() -> {
com.intellij.notification.Notification notification = GROUP_DISPLAY_ID_INFO
.createNotification("<html>TLogin failed", " Go to Settings to setup login data!</html>",
NotificationType.ERROR,
new NotificationListener.UrlOpeningListener(true));
Project[] projects = ProjectManager.getInstance().getOpenProjects();
Notifications.Bus.notify(notification, projects[0]);
});
}
I would like to have a link instead text "LINK!!!", what can you suggest ?
I think that I need to create action and add this action to my group GROUP_DISPLAY_ID_INFO, but this group is not in xml it's just in code exists.
If take my code above as an example, need to add right after new
NotificationListener.UrlOpeningListener(true))
addAction(new NotificationAction("Settings") {
#Override
public void actionPerformed (#NotNull AnActionEvent anActionEvent,
#NotNull Notification notification){
DataContext dataContext = anActionEvent.getDataContext();
Project project = PlatformDataKeys.PROJECT.getData(dataContext)
ShowSettingsUtil.getInstance().showSettingsDialog(project,
YOURCLASS.class);
}
Where yourclass.class is a class which implements Configurable interface
And now on click on Settings you will see opened settings window (yourclass.class)
private static void showMyMessage(String LINK) {
ApplicationManager.getApplication().invokeLater(() -> {
Notification notification = GROUP_DISPLAY_ID_INFO
.createNotification("<html>TLogin failed", " Go to Settings to setup login data!</html>",
NotificationType.ERROR,
new NotificationListener.UrlOpeningListener(true));
Project[] projects = ProjectManager.getInstance().getOpenProjects();
Notifications.Bus.notify(notification, projects[0]);
});
}
Just replace the link as a parameter, and use it like showMyMessage("http://google.com")
Also you don't need to config the group display id in xml, just write the id in code.
I'm new to Cuba Platform and I'm trying to add functionality to copy a record in a table. Essentially the same functionality as found in the Administration -> Users -> Copy User screen.
The button action for this is usersTable.copy
Adding a similar action for example booksTable.copy doesn't seem to work natively. What method do I need to add or anything else to get this to work?
I've gone through the documentation and there's only an example using usersTable.
Many thanks in advance
The users copy action is not something that is generally available (like the create action). But you can look at the implementation from the copy action of the users browser.
Basically it just copies the data from the old user (roles, security group etc.) and prefills the data and then just opens the normal editor of the user like this:
public void copy() {
// fetches the selected user
Set<User> selected = usersTable.getSelected();
User selectedUser = selected.iterator().next();
selectedUser = dataSupplier.reload(selectedUser, "user.edit");
// creates a new user
User newUser = metadata.create(User.class);
// copies the roles and other stuff
if (selectedUser.getUserRoles() != null) {
List<UserRole> userRoles = new ArrayList<>();
for (UserRole oldUserRole : selectedUser.getUserRoles()) {
//...
userRoles.add(role);
}
newUser.setUserRoles(userRoles);
}
newUser.setGroup(selectedUser.getGroup());
// opens the editor with the pre filled data from the other user
AbstractEditor editor = openEditor("sec$User.edit", newUser //...
}
My solution with Cuba-Platform Tools:
public void copy() {
Books selected = booksDs.getItem();
CommitContext context = new CommitContext();
Books copy = metadata.getTools().deepCopy(selected);
copy.setId(uuidSource.createUuid());
copy.setBookName("(COPY) " + booksDs.getItem().getBookName());
context.addInstanceToCommit(copy);
dataManager.commit(copy);
booksDs.refresh();
}
I'm working on a WP8 app and want to hold a text in a textblock when I switch to another page.
So when I come back at the page with the textblock, the text must be still there.
Does anyone know a way for doing this?
Thanks
(Example is in C#, sorry ...)
One way of persisting data is to use Isolated Storage, specifically Application Settings. A simple example of how to do this is:
On the Page's "OnNavigatedFrom" event, add data to storage
On the Page's "OnNavigatedTo" event, retrieve from storage
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
// textBlock is a TextBlock defined in XAML.
if (!settings.Contains("userData"))
settings.Add("userData", textBlock.Text);
else
settings["userData"] = textBlock.Text;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains("userData"))
textBlock.Text = (string)settings["userData"];
}