How to make an Android widget - android-widget

Added a widget to a project and edited the result to show a simple counter -- or so I thought.
class TestWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
val prefs: SharedPreferences = context.getSharedPreferences("TestWidget", 0)
val n:Int = prefs.getInt("n", 1)
val e = prefs.edit()
e.putInt("n", n + 1)
e.apply()
e.commit()
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId, n)
}
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
}
internal fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
value:Int
) {
val widgetText = context.getString(R.string.appwidget_text)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.test_widget)
views.setTextViewText(R.id.appwidget_text, value.toString())
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
In test_widget_info.xml I changed updatePeriodMillis to 500.
I can add the widget to the home screen, but neither updateAppWidget nor onUpdate are never called.
However something must update the widget because the TextView has its text set to EXAMPLE but when running it is changed to Problem loading widget.
Is it possible to make this work? Is it possible to make a widget? Is this documented anywhere?

It can't update more than once every 30 minutes.
https://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo.html#updatePeriodMillis
Workarounds suggest either a Service or a Timer, but do not explain how.

Related

My boolean bloc state variable stops changing after the first reassignment

I am relatively new at flutter. I am creating a timer app using bloc. In the timer you are supposed to have a session, then a break and so on and so forth. To track which type of session to start(a break or session), I am using a boolean value isBreak which I am tracking in the SessionsBloc.
Here is the definition of the SessionsState:
part of 'sessions_bloc.dart';
abstract class SessionsState extends Equatable { final bool isBreak; final int sessionCount; const SessionsState(this.isBreak, this.sessionCount);
#override List<Object> get props => []; }
class SessionsInitial extends SessionsState { const SessionsInitial(super.isBreak, super.sessionCount); }
class SessionTrackingState extends SessionsState { const SessionTrackingState(super.isBreak, super.sessionCount); }
I then use A BlocListener to check for the TimerFinishedState from another bloc TimerBloc, after which I add an event, SessionTrackingEvent, that is supposed to change the aforementioned boolean value.
Here is the code for the listener:
listener: (context, state) {
Task currentTask =
BlocProvider.of<TasksBloc>(context).state.currentTask;
bool isTimeBoxed = currentTask.isTimeBoxed;
int sessionDuration;
int breakDuration;
if (state is TimerCompleteState) {
//Get the SessionsBloc state
final sessionState = BlocProvider.of<SessionsBloc>(context).state;
//Get the current value of the isBreak boolean value
bool isBreak = sessionState.isBreak;
int sessionCount = sessionState.sessionCount;
//Print statements: Can't Debug properly yet:(
print(sessionState.isBreak);
print(sessionState.sessionCount);
if (isTimeBoxed) {
sessionDuration = currentTask.sessionTimeBox!;
breakDuration = currentTask.breakTimeBox ?? 2;
// sessionCount = HiveDb().getTaskSessionCount(currentTask.taskName);
} else {
sessionDuration = 5;
breakDuration = 3;
}
if (isBreak) {
//Set timer with duration time
BlocProvider.of<TimerBloc>(context)
.add(InitializeTimerEvent(duration: sessionDuration));
//Add Event to track session count and next countdown if break or session
BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
isBreak: isBreak,
sessionCount: sessionCount,
));
} else {
//Add event to reset timer
BlocProvider.of<TimerBloc>(context)
.add(InitializeTimerEvent(duration: breakDuration));
//Emit a state that notifies Button Bloc that it's a break and deactivate repeat button.
BlocProvider.of<TimerBloc>(context)
.add(OnBreakEvent(duration: breakDuration));
//Add Event to track session count and next countdown if break or session
BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
isBreak: isBreak,
sessionCount: sessionCount += 1,
));
}
}
},
Finally, in the SessionsBloc, I only have super constructor which initializes the boolean value to false and one event handler that is supposed to change it as appropriate.
class SessionsBloc extends Bloc<SessionsEvent, SessionsState> {
SessionsBloc() : super(const SessionsInitial(false, 0)) {
on<SessionTrackingEvent>((event, emit) {
emit(SessionTrackingState(
event.isBreak ? false : true, event.sessionCount));
});
}
}
The expected result is that for each SessionTrackingEvent added, the boolean should be toggled to the opposite value. However, what actually happens is that it Works the first time, turning the initialized value of false to true and from there it just stays the same. Here is a screenshot of my print statement which outputs the value of IsBreak after every call to SessionTrackingEvent.
Here is a screenshot of my print statement which outputs the value of IsBreak after every call to SessionTrackingEvent.
I have tried changing the variable type from final because I thought maybe it's a flutter constraint about reassigning variables.
I have tried moving the reading of the block state value into the build method outside of the listener because I thought maybe it doesn't read the value as frequently.
What could be the problem, what might be preventing the value from changing as appropriate?
You forgot to pass your SessionsState properties into props list, so the Bloc can't differentiate between old and new states without it.
abstract class SessionsState extends Equatable {
final bool isBreak;
final int sessionCount;
const SessionsState(this.isBreak, this.sessionCount);
#override
List<Object> get props => [isBreak, sessionCount]; // your props should go here like this
}

what is Get.create() in the Getx package and what it does

reading the Getx package documentation, I faced this method:
Get.create<ShoppingController>(() => ShoppingController());
and it says:
Get.create(()=>Controller()) will generate a new Controller each time you call Get.find(),
but, I don't seem to understand what this means and how it differs from the Get.put() and Get.lazyPut().
I found the answer for that question.
The big difference between
Get.create<ShoppingController>(() => ShoppingController());
And :
Get.put(ShoppingController());
Both of them are used in injecting dependencies in the a Flutter app, But Get.put<T>(T()) injects it just one time and whenever we call Get.find<T>() it looks up for that exact dependency and return it, so we can rememeber this:
Get.put<T>(()) inject a dependency and whatever time we call Get.find<T>() across the entire app, the same T is returned.
In the other side, Get.create<V>(() => V) also inject a dependency in a Flutter app, But every time we call Get.find<V>(), it doesn't return the same V, it creates a new instance of V, then return it, so we can rememeber this:
Get.create<V>(() => V) don't return the same instance, it creates a new one every time Get.find<V>() is called.
Get.put(T()) :
class ControllerOne extends GetxController {
int number = 10;
increment() {
number += 10;
}
}
final controllerOne = Get.put<ControllerOne>(ControllerOne());
final controllerOneFinder = Get.find<controllerOne>();
controllerOneFinder.increment();
final controllerOneSecondFinder = Get.find<controllerOne>();
print(controllerOneFinder.number); // 20
print(controllerOneSecondFinder.number); // 20
it stay the same.
Get.create(() =>T) :
class ControllerTwo extends GetxController {
int secondNumber = 10;
increment() {
secondNumber += 10;
}
}
final controllerTwo = Get.create<ControllerTwo>(() => (ControllerTwo());
final controllerTwoFinder = Get.find<ControllerTwo>();
controllerTwoFinder.increment();
final controllerTwoSecondFinder = Get.find<ControllerTwo>();
print(controllerTwoFinder.number); // 20
print(controllerTwoSecondFinder.number); // 10
Each one is different than the other. (controllerTwoSecondFinder == controllerTwoFinder) is false.

How do I pass a function from a ViewModel to my scaffold's floating action button in Jetpack Compose?

I'm building an Android app using purely Jetpack Compose. My entire application is wrapped under one scaffold, and has a ViewModel for each "screen" (which are composables) in my app. Because of that, I have some conditional statements in my scaffold to determine the floating action button (FAB) based on the route. However, one of the FABs needs access to a function in a ViewModel, which is only created when I navigate to the route that holds that composable, and I'm at a loss on the best way to give the FAB access to that viewmodel function.
Take the following example (based off my code), and note the FAB for the route "route3".
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
#Composable
fun MyApp() {
val navController = rememberNavController()
val backstackEntry = navController.currentBackStackEntryAsState()
val scaffoldState = rememberScaffoldState()
Surface(color = MaterialTheme.colors.background) {
Scaffold(
topBar = { ... },
bottomBar = { ... },
floatingActionButton = {
when (backstackEntry.value?.destination?.route) {
"route2" -> FAB2(navController)
"route3" -> FAB3(navController) // Needs to access function from viewModel3
}
},
scaffoldState = scaffoldState,
) {
MyNavHost(navController, scaffoldState)
}
}
}
#Composable
fun MyNavHost(navController: NavHostController, scaffoldState: ScaffoldState) {
NavHost(
navController = navController,
startDestination = "route1"
) {
composable("route1") { Destination1() }
composable("route2") { Destination2() }
composable("route3") { Destination3() }
}
}
#Composable
fun Destination1() { ...}
#Composable
fun Destination2() { ... }
#Composable
fun Destination3() {
val viewModel3: CustomViewModel = hiltViewModel()
Screen3(viewModel3)
}
}
So my main question is, if the FAB3 variable needs to access a function from viewModel3, how would I go about doing it?
I decided to just switch over to using a scaffold for every screen.
Honestly, this makes managing routes a lot easier, because in the single scaffold scenario, it was getting difficult managing all of the possible routes for things like the TopBar and FAB in large when() blocks.
But if anyone has a solution to the original question that would be appreciated!

Native Dialog for location setting on Flutter

Is there a way to implement a Dialog for Location setting like the image below which gets triggered when app requires GPS location and doesn't find. Hitting OK will right away turn on the system GPS. This seems more convenient for users instead of taking them to location and manually turn on.
Is it possible to implement such thing in Flutter?
Expanded View of dialog:
Credits to Rajesh, as answered here. The plugin lets you add this native dialog for a quick location setting.
The implementation is quite simple as this:
import 'package:location/location.dart';
var location = Location();
Future _checkGps() async {
if(!await location.serviceEnabled()){
location.requestService();
}
}
#override
void initState() {
super.initState();
_checkGps();
}
In Kotlin, try this code:
class HomeActivity : AppCompatActivity() {
private val requestLocation = 199
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableLoc()
}
private fun enableLoc() {
val mLocationRequest = LocationRequest.create()
mLocationRequest.interval = 10000
mLocationRequest.fastestInterval = 5000
// mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest)
val client = LocationServices.getSettingsClient(this)
val task =
client.checkLocationSettings(builder.build())
task.addOnSuccessListener(this) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
task.addOnFailureListener(this) { e ->
if (e is ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
e.startResolutionForResult(
this,
requestLocation
)
} catch (sendEx: SendIntentException) {
// Ignore the error.
}
}
}
}
}

GWT - How to retrieve real clicked widget?

I have onClick event on somePanel. And I click on it and it works. But.. How to retrieve real click target? When I click on panel which is inside od somePanel it show me that I click on somePanel..
I know we have this:
Element e = Element.as( event.getNativeEvent().getEventTarget());
But i returns element - I want widget..
How to do this?
This is an old question, but both answers are wrong. If you are using a GWT EventListener and want the widget that is the source of the event, then you simply use the event.getSource() method of the event and cast it to the original object type.
Unless there is something that I am missing in the question here.
I would use the feature in gwtquery to get the widget associated with a given element: https://code.google.com/p/gwtquery/wiki/GettingStarted#Manipulating_your_widgets
Widget = $(e).widget();
The problem is that the element clicked couldn't be the element associated with the widget but a child. In this case you could use gquery selectors to traverse the dom until you get its parent widget based on some css property.
// Most gwt widgets contains a class .gwt- but this could fail
// so use a more accurate selector than the one in this example
Widget = $(e).closest("[class*='.gwt-']")
If you wanted to do it by yourself, taking a look to the method getAssociatedWidget in GQuery gives you the solution:
EventListener listener = DOM.getEventListener(e);
// No listener attached to the element, so no widget exist for this element
if (listener == null) {
return null;
}
if (listener instanceof Widget) {
// GWT uses the widget as event listener
return (Widget) listener;
}
EDITED: here you have a working example:
import static com.google.gwt.query.client.GQuery.*;
// A panel with some widgets
Panel panel = new VerticalPanel();
final HTML widget1 = new HTML("<span>Foo</span> <span>Bar</span");
final HTML widget2 = new HTML("<span>Foo</span> <span>Bar</span");
final HTML widget3 = new HTML("<span>Foo</span> <span>Bar</span");
panel.add(widget1);
panel.add(widget2);
panel.add(widget3);
// we need to wrap our panel with a widget supporting click events
FocusPanel wrapper = new FocusPanel();
wrapper.add(panel);
RootPanel.get().add(wrapper);
wrapper.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// The element is not the HTML widget clicked but the span element
Element e = event.getNativeEvent().getEventTarget().cast();
// Using gquery to get the closest widget to the clicked element
// We take advanrage of HTML widgets having gwt-HTML class
Widget w = $(e).closest(".gwt-HTML").widget();
if (w == widget1) {
Window.alert("Clicked on widget 1");
} else if (w == widget2) {
Window.alert("Clicked on widget 2");
} else if (w == widget3) {
Window.alert("Clicked on widget 3");
} else {
Window.alert("Clicked on a non GWT HTML widget");
}
}
});
An alternative approach, if you already know all of the widgets that you want to check against, would be to use the DOM.isOrHasChild(Element) or Element.isOrHasChild(Node).
For example:
public void onClick(ClickEvent event) {
Element targetElem = Element.as(event.getNativeEvent().getEventTarget());
Widget targetWidget = null;
if (widgetA.getElement().isOrHasChild(targetElem) {
targetWidget = widgetA;
}
else if (widgetB.getElement().isOrHasChild(targetElem) {
targetWidget = widgetA;
}
.....
if (targetWidget != null) {
// You found you widget - Yay!
}
else {
// No widget found - Bummer!
}
}
This approach only works if you know the widgets you are testing against up front. The benefit is that you now have an particular widget reference rather then a generic reference to 'some' widget that you might have to do additional checks against.
For example, you could have done the following if widgetA was a subclass of TextBox called MySpecialTextBox:
MySpecialTextBox widgetA;
if (widgetA.getElement().isOrHasChild(targetElem) {
widgetA.someSpecialMethod();
}