[Apple Store]restrict the locations

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Re: [Apple Store]restrict the locations

Postby rlebeau » Wed Nov 28, 2018 2:05 pm

Lena wrote:I think I add a display of the new TForm. In label write "Sorry this app is only for the state of Colorado USA. Restart this application completely when you are in the state of Colorado USA."


Well, a restart would not be needed. Since you are already tracking location changes, you could simply keep that active for the lifetime of your app's process, and just update your UI as needed whenever the user enters or leaves Colorado while the app is still running.

"You have entered Colorado. You can now use this feature."

"You are leaving Colorado. You can no longer use this feature."
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Thu Nov 29, 2018 3:16 am

you could simply keep that active for the lifetime of your app's process


If I leave LocationSensor1->Active = true event OnGeocodeReverseEvent happens a lot of times. I read that the Google does not like when they often read geodata (no more than 2500 per day). :(

My code now:
Code: Select all
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
 LocationSensor1->Active = true;
 CheckBox1->IsChecked = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
        const TLocationCoord2D &NewLocation)
{
   if (CheckBox1->IsChecked == true)
   {
      //for test
     Edit1->Text = NewLocation.Latitude;
     Edit2->Text = NewLocation.Longitude;
   }

   try
    {
     if(fGeocoder == NULL)
      {
       if(TGeocoder::Current != NULL)
         {
         fGeocoder = (TGeocoder*)new TGeocoderClass(TGeocoder::Current);
           }

       if(fGeocoder != NULL)
         {
         fGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;
           }

      }

     if((fGeocoder != NULL) && (!fGeocoder->Geocoding()))
       {

        //TLocationCoord2D TestCoordinates;
        //TestCoordinates.Latitude = 39.739170;
        //TestCoordinates.Longitude = -104.984720;
        //fGeocoder->GeocodeReverse(TestCoordinates);
        fGeocoder->GeocodeReverse(NewLocation);
         }

    }
    catch (...)
        {
         //const Exception &E
         //String MES =  E.Message;
         //ShowMessage(L"Ошибка: " + MES);
        }


}
//---------------------------------------------------------------------------

 void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {

  if (!Address) return;

   String country = Address->CountryName;
   String state = Address->AdminArea;

   //for test;
   Memo1->Lines->Add(country);
   Memo1->Lines->Add(state);

   bool checkcountry = SameText(country, L"USA") ||
                  SameText(country, L"United States of America");// ||
                  //SameText(country, L"Украина"); my country fot test

   bool checkstate = SameText(state, L"CO") ||
                 SameText(state, L"Colorado");// ||
                 //SameText(state, L"Черновицкая область");

   if (checkcountry && checkstate)
   {
      //just show Main Form
        /*
      //test code
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in the state of Colorado USA.";
      MyNewForm->ButtonClose->Visible = true; //Close MyNewForm
      LocationSensor1->Active = false;
      MyNewForm->Show();
      */
     LocationSensor1->Active = false;
    }
   else
   {
      String mark = L"You are in the " + Address->CountryName + " " + Address->AdminArea + ". " +
      "Sorry this app is only for the state of Colorado USA.";
      MyNewForm->Text1->Text = mark;
      MyNewForm->ButtonClose->Visible = false;
      LocationSensor1->Active = false;
        MyNewForm->Show();

   }
 }
 //---------------------------------------------------------------------------



At the very first start of the application, a ios window appears asking the system to allow or not access to geodata. How to understand that the user pressed the button to ban, well, then close the application.



iOS has an API for that (see Choosing the Authorization Level for Location Services), but I don't know how to utilize that in C++Builder. You will likely have to access iOS's CLLocationManager API directly for that.


It's hard for me to use ios api...
May try to use a timer?
Code: Select all
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  if(fGeocoder == NULL)
   {
   String mark = L"Sorry this app needs access to geodata.";
   MyNewForm->Text1->Text = mark;
   MyNewForm->ButtonClose->Visible = false;
   LocationSensor1->Active = false;
   MyNewForm->Show();
   Timer1->Enabled = false;
   }
}


But I do not know what interval to use?
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Thu Nov 29, 2018 11:24 am

Lena wrote:If I leave LocationSensor1->Active = true event OnGeocodeReverseEvent happens a lot of times.


Only if you geocode often. Just because you may get a lot of OnLocationChanged events triggered does not mean you have to geocode every one of them. Throttle your calls. You don't need to geocode every individual coordinate change. People tend to stay in one place for arbitrary periods of time, especially times when they are at home or work or whatever, so their location shouldn't change very much, or it will change in small increments at a time, depending on the granularity of the device's GPS receiver.

Lena wrote:I read that the Google does not like when they often read geodata (no more than 2500 per day). :(


At worse, that works out to ~1-2 requests per minute over a 24 hour period. You could easily throttle your code to limit how many requests you make, say 5-10 per minute for instance. Then you would be making only a few hundred requests a day, instead of a few thousand.

But, if you take into account that location shouldn't change very much, or it will change in small increments, you can reduce how many requests you make per 24 hours. The OnLocationChanged event gives you previous and current coordinates, so you can easily calculate the distance the device has moved between each GPS update. Maybe you don't geocode until the device moves more than a set distance at a time, say 1-5 miles at a time.

Apple's documentation says:

- When you want to update the location automatically (such as when the user is moving), reissue the geocoding request only when the user's location has moved a significant distance and after a reasonable amount of time has passed. In general, you shouldn’t send more than one geocoding request per minute.

- Don’t start a geocoding request if the user won’t see the results immediately. For example, don’t start a request if your app is in the background or was interrupted and is currently in the inactive state.


So, if your app is hidden/in the background, don't geocode again until it comes to the foreground, and then update your UI for the current location.

To take that a step further, if geocoding says the device is not even in the USA at all, you don't need to geocode again for a long while, maybe even not for hours at a time (at least the fastest time needed to reach Colorado from the West or South borders of the USA, which are the closest USA borders to Colorado).

Even if the device is in the USA, you can geocode less often if the device is not in Colorado or its immediate surrounding states (Wyoming, Nebraska, Kansas, Oklahoma, Texas, New Mexico, Arizona, or Utah). Once the device is in one those states, then geocode a little more often to detect if/when the device crosses Colorado's border.

Or, you could just hard-code the known coordinates of Colorado's borders (or at least its 4 corners, since it is a fairly rectangular-shaped state), and then geocode only when the device is within a set distance of those borders, say 5-10 miles for instance.

In other words, throttle how often you geocode based on how close or far the device's current location is to Colorado. The farther away the location is, the less often you need to geocode. The closer the location is, the more often you need to geocode. Be strategic in your use of geocoding, don't just use it blindly.

Lena wrote:It's hard for me to use ios api...


I suggest you learn how. Start by looking at TGeocoder's own source code, porting it from Delphi to C++, and then tweak it for the extra parameters you need.
Last edited by rlebeau on Mon Dec 03, 2018 1:26 pm, edited 4 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Mon Dec 03, 2018 6:04 am

Thank you very much for the detailed information!
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby Lena » Mon Dec 03, 2018 11:19 am

I still can not understand one thing.
Code: Select all
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
  LocationSensor1->Active = true;
}

Start first time app press Allow location. All fine I see MyNewForm with welcome message. Close app + unload the application from the phone's memory. Star app and I don't see MyNewForm with welcome message. Why doesn’t an event OnGeocodeReverseEvent occur during the second start of the application? I want see MyNewForm every time when app start. Is it possible?
Code: Select all
bool badlocation = true;
bool goodlocation = true;

bool __fastcall TForm1::CheckGeocode()
{
  if(goodlocation == false)
   {
   return true;
   }
  //fGeocoder = NULL if user press do not alow location
  if(badlocation == false || fGeocoder == NULL)
  {
   String mark = "This feature is not available. Please make sure that you have access to Location allowed and that you are in the Colorado USA.";
   ShowMessage(mark);
   return false;
  }
  else
    {
     return true;
    }
}

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
  LocationSensor1->Active = true;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
        const TLocationCoord2D &NewLocation)
{
 try
    {
     if(fGeocoder == NULL)
      {
       if(TGeocoder::Current != NULL)
         {
         fGeocoder = (TGeocoder*)new TGeocoderClass(TGeocoder::Current);
         }

       if(fGeocoder != NULL)
         {
         fGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;

         }

      }

     if((fGeocoder != NULL) && (!fGeocoder->Geocoding()))
       {

        //TLocationCoord2D TestCoordinates;
        //TestCoordinates.Latitude = 39.739170;
        //TestCoordinates.Longitude = -104.984720;
        //fGeocoder->GeocodeReverse(TestCoordinates);
        fGeocoder->GeocodeReverse(NewLocation);
       }

    }
    catch (...)
        {
         //const Exception &E
         //String MES =  E.Message;
         //ShowMessage(L"Ошибка: " + MES);
        }


}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {

  if (goodlocation == false) return;
  if (badlocation == false) return;
  if (!Address) return;


   String country = Address->CountryName;
   String state = Address->AdminArea;

   bool checkcountry = SameText(country, L"USA") ||
                  SameText(country, L"United States of America") ||
                  SameText(country, L"Украина"); //my country fot test

   bool checkstate = SameText(state, L"CO") ||
                 SameText(state, L"Colorado") ||
                 SameText(state, L"Черновицкая область");

   if (checkcountry && checkstate)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in the state of Colorado USA. All application features are available.";
      LocationSensor1->Active = false;
        goodlocation = false;
      MyNewForm->Show();

   }
   else
   {
      String mark = L"You are in the " + Address->CountryName + " " + Address->AdminArea + ". " +
      "Sorry this app is only for the state of Colorado USA. You can not use all the features of the application.";
      MyNewForm->Text1->Text = mark;
      badlocation = false;
      fGeocoder = NULL;
      LocationSensor1->Active = false;
      MyNewForm->Show();

   }

 }
 //---------------------------------------------------------------------------



Every time LocationSensor1->Active = true; but I see MyNewForm only when first start the application. I just want to understand the problem for myself.
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Mon Dec 03, 2018 1:51 pm

Lena wrote:Start first time app press Allow location. All fine I see MyNewForm with welcome message. Close app + unload the application from the phone's memory. Star app and I don't see MyNewForm with welcome message. Why doesn’t an event OnGeocodeReverseEvent occur during the second start of the application?


I can't answer that. Are you getting an OnLocationChanged event on the second app start? Are you performing a geocode operation at that time? Are you even debugging your app to see what it actually does each time it starts?

Maybe the device caches the last known location and does not fire a new OnLocationChanged event until the location actually changes, even across app sessions. Who knows. That is why you need to debug your app at runtime. If you are not getting a new event at every app start, then you will have to manually query the device's current location at startup. Look at the sensor's Latitude and Longitude properties.

Lena wrote:I want see MyNewForm every time when app start. Is it possible?


Of course it is possible, it is just a matter of HOW you determine where the device is currently located at app start. For example:

Code: Select all
private:
   bool IsInColorado;
...

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
   IsInColorado = false;
   LocationSensor1->Active = true;

   TLocationCoord2D CurrentCoordinates;
   CurrentCoordinates.Latitude = LocationSensor1->Latitude;
   CurrentCoordinates.Longitude = LocationSensor1->Longitude;
   DoGeocode(CurrentCoordinates);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation, const TLocationCoord2D &NewLocation)
{
   //TLocationCoord2D TestCoordinates;
   //TestCoordinates.Latitude = 39.739170;
   //TestCoordinates.Longitude = -104.984720;
   //DoGeocode(TestCoordinates);
   DoGeocode(NewLocation);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DoGeocode(const TLocationCoord2D &Location)
{
   try
   {
      if (!fGeocoder)
      {
         if (TGeocoder::Current)
         {
            fGeocoder = (TGeocoder*) new TGeocoderClass(TGeocoder::Current);
            fGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;
         }
      }

      if ((fGeocoder) && (!fGeocoder->Geocoding()))
         fGeocoder->GeocodeReverse(Location);
   }
   catch (...)
   {
      //const Exception &E
      //String MES =  E.Message;
      //ShowMessage(L"Ошибка: " + MES);
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
{
   if (!Address) return;

   String country = Address->CountryName;
   String state = Address->AdminArea;

   bool checkcountry = SameText(country, L"USA") ||
                  SameText(country, L"United States of America") ||
                  SameText(country, L"Украина"); //my country fot test

   bool checkstate = SameText(state, L"CO") ||
                 SameText(state, L"Colorado") ||
                 SameText(state, L"Черновицкая область");

   IsInColorado = (checkcountry && checkstate);
   if (IsInColorado)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in Colorado USA. All application features are available.";
   }
   else
   {
      //user not in Сolorado
      MyNewForm->Text1->Text = L"You are in " + Address->AdminArea + L" " + Address->CountryName + L". This app is only for Colorado USA. You can not use all application features.";
   }

   MyNewForm->Show();
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::CheckGeocode()
{
   if (!IsInColorado)
   {
      String mark = L"This feature is not available. Please make sure that you have allowed access to Location services and that you are in Colorado USA.";
      ShowMessage(mark);
   }
   return IsInColorado;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Tue Dec 04, 2018 5:40 am

Are you getting an OnLocationChanged event on the second app start?


Yes.

Are you performing a geocode operation at that time?


No.


Are you even debugging your app to see what it actually does each time it starts?


I think this is a FMX bug. I set a breakpoint on the line MyNewForm->Show() Every time I start the application, I get to this breakpoint.
Code: Select all
   if (checkcountry && checkstate)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in the state of Colorado USA. All application features are available.";
      LocationSensor1->Active = false;
      goodlocation = false;
      MyNewForm->Show();//<--I am here every time I start the application!!! But this line stops showing form after the second start.


   }



I remove MyNewForm. Instead, I used TRectangle with Align=Content and Visible=false.
But the problem remained. I added a new line of code and it looks like everything went well.
Code: Select all
   if (checkcountry && checkstate)
   {
      //user in Сolorado
      //MyNewForm->Text1->Text = L"Welcome. You are in the state of Colorado USA. All application features are available.";
      Text1->Text = L"Welcome. You are in the state of Colorado USA. All application features are available.";
      Rectangle4->Visible = true;
      Application->ProcessMessages();//<-- THIS LINE
      LocationSensor1->Active = false;
      goodlocation = false;

   }


Thank you very much for your code! I try but:
CurrentCoordinates.Latitude = LocationSensor1->Latitude;
[bcciosarm64 Error] UnitINI.cpp(93): no member named 'Latitude' in 'System::Sensors::Components::TLocationSensor'
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Tue Dec 04, 2018 12:19 pm

Lena wrote:
Are you getting an OnLocationChanged event on the second app start?


Yes.

Are you performing a geocode operation at that time?


No.


Well, then that answers your question about why the OnGeocodeReverse event does not occur during the second start of the application. Why are you not performing a geocode during the second app startup?

Lena wrote:
Code: Select all
MyNewForm->Show();//<--I am here every time I start the application!!! But this line stops showing form after the second start.


So, then you ARE getting an OnGeocodeReverse event triggered on the second app start. You are contradicting yourself.

Lena wrote:I added a new line of code and it looks like everything went well.


Any time you have to resort to calling Application->ProcessMessages(), you should your code design. In this case, I would suggest trying to have the OnGeocodeReverse event handler use TThread::ForceQueue() (Tokyo+) or TThread::CreateAnonymousThread()+TThread::Queue() (pre-Tokyo) to update your UI asynchronously (we've been down that road before), instead of doing it inside the event handler directly. For example:

Code: Select all
private:
    bool IsInColorado;
...

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    IsInColorado = false;
    LocationSensor1->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation, const TLocationCoord2D &NewLocation)
{
    //TLocationCoord2D TestCoordinates;
    //TestCoordinates.Latitude = 39.739170;
    //TestCoordinates.Longitude = -104.984720;
    //DoGeocode(TestCoordinates);
    DoGeocode(NewLocation);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DoGeocode(const TLocationCoord2D &Location)
{
    try
    {
        if (!fGeocoder)
        {
            if (TGeocoder::Current)
            {
                fGeocoder = (TGeocoder*) new TGeocoderClass(TGeocoder::Current);
                fGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;
            }
        }

        if ((fGeocoder) && (!fGeocoder->Geocoding()))
            fGeocoder->GeocodeReverse(Location);
    }
    catch (...)
    {
        //const Exception &E
        //String MES =  E.Message;
        //ShowMessage(L"Ошибка: " + MES);
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
{
    if (!Address) return;

    String country = Address->CountryName;
    String state = Address->AdminArea;

    bool checkcountry = SameText(country, L"USA") ||
                      SameText(country, L"United States of America") ||
                      SameText(country, L"Украина"); //my country fot test

    bool checkstate = SameText(state, L"CO") ||
                     SameText(state, L"Colorado") ||
                     SameText(state, L"Черновицкая область");

    IsInColorado = (checkcountry && checkstate);

    TThread::ForceQueue(nullptr, &GeocodeFinished);
    //TThread::CreateAnonymousThread([this](){ TThread::Queue(nullptr, &GeocodeFinished); })->Start();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::GeocodeFinished()
{
    if (IsInColorado)
    {
        //user in Сolorado
        MyNewForm->Text1->Text = L"Welcome. You are in Colorado USA. All application features are available.";
    }
    else
    {
        //user not in Сolorado
        MyNewForm->Text1->Text = L"You are in " + Address->AdminArea + L" " + Address->CountryName + L". This app is only for Colorado USA. You can not use all application features.";
    }

    MyNewForm->Show();
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::CheckGeocode()
{
    if (!IsInColorado)
    {
        String mark = L"This feature is not available. Please make sure that you have allowed access to Location services and that you are in Colorado USA.";
        ShowMessage(mark);
    }
    return IsInColorado;
}


Lena wrote:I try but:
CurrentCoordinates.Latitude = LocationSensor1->Latitude;
[bcciosarm64 Error] UnitINI.cpp(93): no member named 'Latitude' in 'System::Sensors::Components::TLocationSensor'


Nevermind. Latitude and Longtitude are properties of TCustomLocationSensor, which apparently TLocationSensor does not derive from, despite its name (bad naming scheme, Embarcadero!).

But that issue is moot now, since you have now claimed that you are, in fact, getting the OnGeocodeReverse event triggered on every app startup.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Tue Dec 04, 2018 11:30 pm

Well, then that answers your question about why the OnGeocodeReverse event does not occur during the second start of the application. Why are you not performing a geocode during the second app startup?


I am sorry, this is my bad English, I did not understand the question correctly. The answer is yes.

When I added two variables bool and Application->ProcessMessages() мy application began to work correctly. I analyze 4 states:
1. User is not in Colorado.
a) At the start of the application, the user denied access to the location. In this case, the user does not see the welcome window. BUT! When user click on some buttons in the application, the user receives a message:
This feature is not available. Please make sure that you have access to Location allowed and that you are in the Colorado USA.
b) At the start of the application, the user allows access to the location. In this case, he sees a window with the message:
You are in the " + Address->CountryName + " " + Address->AdminArea + ". " + "Sorry this app is only for the state of Colorado USA. You can not use all the features of the application.
When user close this window and phess some button in main form he receives a message:
This feature is not available. Please make sure that you have access to Location allowed and that you are in the Colorado USA.

2. User in Colorado.
a) The same 1a.
b) At the start of the application, the user allows access to the location. In this case, he sees a window with the message:
Welcome. You are in the state of Colorado USA. All application features are available.
When user close this window all buttons are available on the main form.

It seems to me that everything looks right and logical enough.

Now I will try your recommendation to use TThread instead ProcessMessages and other your code and mix it with my two variables bool. :)

P.S.
Code: Select all
//-----------------------------------------------
void __fastcall TForm1::GeocodeFinished()
{
   if (IsInColorado)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in Colorado USA. All application features are available.";
   }
   else
   {
      //user not in Сolorado
      MyNewForm->Text1->Text = L"You are in " + Address->AdminArea + L" " + Address->CountryName + L". This app is only for Colorado USA. You can not use all application features.";
   }

   MyNewForm->Show();
}
   

Error because no access to Address.

I try:
Code: Select all
public:      
   bool __fastcall CheckGeocode();
   void __fastcall GeocodeFinished(TCivicAddress* const Address);
//********************************************************************************

void __fastcall TForm1::GeocodeFinished(TCivicAddress* const Address)
{
   if (IsInColorado)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in Colorado USA. All application features are available.";
   }
   else
   {
      //user not in Сolorado
      MyNewForm->Text1->Text = L"You are in " + Address->AdminArea + L" " + Address->CountryName + L". This app is only for Colorado USA. You can not use all application features.";
   }

   MyNewForm->Show();
}

void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {

   if (!Address) return;

      String country = Address->CountryName;
      String state = Address->AdminArea;

      bool checkcountry = SameText(country, L"USA") ||
                    SameText(country, L"United States of America") ||
                    SameText(country, L"Украина"); //my country fot test

      bool checkstate = SameText(state, L"CO") ||
                   SameText(state, L"Colorado") ||
                   SameText(state, L"Черновицкая область");

      IsInColorado = (checkcountry && checkstate);

      TThread::ForceQueue(nullptr, &GeocodeFinished(Address)); //<-- error
      //TThread::CreateAnonymousThread([this](){ TThread::Queue(nullptr, &GeocodeFinished); })->Start();

 }

Error cannot take the address of an rvalue of type 'void' :(
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Wed Dec 05, 2018 12:52 pm

Lena wrote:a) At the start of the application, the user denied access to the location. In this case, the user does not see the welcome window. BUT! When user click on some buttons in the application, the user receives a message:
This feature is not available. Please make sure that you have access to Location allowed and that you are in the Colorado USA.


Makes sense. That would be reasonable behavior when the user tries to access a feature that requires the device to be in a particular location.

Though, I would suggest you consider tweaking the message text to leave off the Colorado portion if access to Location services has been denied. Don't mention the actual location by name unless you are allowed to determine the device's location.

Lena wrote:b) At the start of the application, the user allows access to the location. In this case, he sees a window with the message:
You are in the " + Address->CountryName + " " + Address->AdminArea + ". " + "Sorry this app is only for the state of Colorado USA. You can not use all the features of the application.


Again, makes sense.

You might consider displaying some kind of status UI while determining the current location.

Lena wrote:When user close this window and phess some button in main form he receives a message:
This feature is not available. Please make sure that you have access to Location allowed and that you are in the Colorado USA.


Again, reasonable. Though, when access to the Location is denied, or the device is not in the correct location, you should just hide access to the feature to begin with, so the user can't even click on it.

Lena wrote:b) At the start of the application, the user allows access to the location. In this case, he sees a window with the message:
Welcome. You are in the state of Colorado USA. All application features are available.
When user close this window all buttons are available on the main form.


Reasonable, though it may not be worth displaying a popup message at all once the device enters the correct location. Just enable your feature as needed and move on.

Lena wrote:
Code: Select all
void __fastcall TForm1::GeocodeFinished()
{
   if (IsInColorado)
   {
      //user in Сolorado
      MyNewForm->Text1->Text = L"Welcome. You are in Colorado USA. All application features are available.";
   }
   else
   {
      //user not in Сolorado
      MyNewForm->Text1->Text = L"You are in " + Address->AdminArea + L" " + Address->CountryName + L". This app is only for Colorado USA. You can not use all application features.";
   }

   MyNewForm->Show();
}   


Error because no access to Address.


Sorry, that was a copy/paste mistake on my part. Obviously, you would have to store the current AdminArea and CountryName values to their own variables alongside the IsInColorado variable before then invoking GeocodeFinished(). Or, you could simply leave those values out of the popup message altogether, you could just say something like "You are not in Colorado USA. You can not use all application features" instead.

Lena wrote:
Code: Select all
TThread::ForceQueue(nullptr, &GeocodeFinished(Address)); //<-- error


That will not work. TThread::ForceQueue() requires a procedure that does not take any input parameters.

To do what you are trying, you would have to either:

- store the Address pointer to a variable that remains in scope until GeocodeFinished() is called:

Code: Select all
private:
    void __fastcall GeocodeFinished();
    TCivicAddress* GeocodeAddress;
    ...

void __fastcall TForm1::GeocodeFinished()
{
    // use GeocodeAddress as needed...
}

void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {
    if (!Address) return;
    ...
    GeocodeAddress = Address;
    TThread::ForceQueue(nullptr, &GeocodeFinished);
}


- use a lambda to capture the Address pointer:

Code: Select all
private:
    void __fastcall GeocodeFinished(TCivicAddress* const Address);
    ...

void __fastcall TForm1::GeocodeFinished(TCivicAddress* const Address)
{
    //...
}

void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {
    if (!Address) return;
    ...
    TThread::ForceQueue(nullptr, [=](){ GeocodeFinished(Address); });
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Fri Dec 07, 2018 1:33 am

Thank you very much for your help! I will try your recommendations in new version!

P.S.
I did not know that I would receive the correct code from you and sent the application to the apple store a few days ago. Is this a big mistake if the code is Application->ProcessMessages()?
No response from the apple store yet.
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Fri Dec 07, 2018 1:32 pm

Lena wrote:Is this a big mistake if the code is Application->ProcessMessages()?


It is not a "mistake" per say, but it is a big "code smell" that should be avoided whenever possible.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Mon Dec 17, 2018 4:59 am

Thank you rlebeau very much for your help. The application is published in the apple store. After the publication it turned out that I need to publish the application with the new version and the new code:

bool checkcountry = SameText(country, L"USA") ||
SameText(country, L"United States of America")||
SameText(country, L"United States");<- add this

This was verified by a friend of mine who launched an application in Colorado.

P.S.
Probably it would be better to find the function in C++ Builder if the string contains the right United States?
Lena
BCBJ Master
BCBJ Master
 
Posts: 597
Joined: Sun Feb 06, 2011 1:28 pm

Previous

Return to Technical

Who is online

Users browsing this forum: No registered users and 19 guests