Compare commits
2 Commits
407f45f797
...
4c21600576
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c21600576 | |||
| fdb179d183 |
1
apps/blakus-nativescript/.gitignore
vendored
1
apps/blakus-nativescript/.gitignore
vendored
@ -8,7 +8,6 @@ platforms/
|
|||||||
*.js
|
*.js
|
||||||
!eslint.config.js
|
!eslint.config.js
|
||||||
!webpack.config.js
|
!webpack.config.js
|
||||||
!tailwind.config.js
|
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
|||||||
@ -14,6 +14,9 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.tns.NativeScriptApplication"
|
android:name="com.tns.NativeScriptApplication"
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="_amenity_restaurant_CYImm">"Restaurant"</string>
|
||||||
|
<string name="_amenity_pub_hVjSx">"Pub"</string>
|
||||||
|
<string name="_amenity_ice_cream_12K4Gu">"Ice Cream"</string>
|
||||||
|
<string name="_amenity_food_court_Z2qUk6P">"Food Court"</string>
|
||||||
|
<string name="_amenity_fast_food_Z1zDs8J">"Fast Food"</string>
|
||||||
|
<string name="_amenity_cafe_Z13hX6o">"Cafe"</string>
|
||||||
|
<string name="_amenity_biergarten_zXiC4">"Beer Garden"</string>
|
||||||
|
<string name="_amenity_bar_hVg75">"Bar"</string>
|
||||||
|
<string name="_app_name_1k3Sbz">"Blakus"</string>
|
||||||
|
<string name="app_name">"Blakus"</string>
|
||||||
|
<string name="title_activity_kimera">"Blakus"</string>
|
||||||
|
</resources>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="_amenity_restaurant_CYImm">"Restorāns"</string>
|
||||||
|
<string name="_amenity_pub_hVjSx">"Krogs"</string>
|
||||||
|
<string name="_amenity_ice_cream_12K4Gu">"Saldējums"</string>
|
||||||
|
<string name="_amenity_food_court_Z2qUk6P">"Ēdināšanas laukums"</string>
|
||||||
|
<string name="_amenity_fast_food_Z1zDs8J">"Ātras uzkodas"</string>
|
||||||
|
<string name="_amenity_cafe_Z13hX6o">"Kafejnīca"</string>
|
||||||
|
<string name="_amenity_biergarten_zXiC4">"Biergarten"</string>
|
||||||
|
<string name="_amenity_bar_hVg75">"Bārs"</string>
|
||||||
|
<string name="_app_name_1k3Sbz">"Blakus"</string>
|
||||||
|
<string name="app_name">"Blakus"</string>
|
||||||
|
<string name="title_activity_kimera">"Blakus"</string>
|
||||||
|
</resources>
|
||||||
@ -4,11 +4,12 @@
|
|||||||
"license": "SEE LICENSE IN <your-license-filename>",
|
"license": "SEE LICENSE IN <your-license-filename>",
|
||||||
"repository": "<fill-your-repository-here>",
|
"repository": "<fill-your-repository-here>",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nativescript/core": "*"
|
"@nativescript/core": "*",
|
||||||
|
"@nativescript/geolocation": "^9.0.0",
|
||||||
|
"@nativescript/localize": "^5.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nativescript/android": "~8.8.0",
|
"@nativescript/android": "~8.8.0",
|
||||||
"@nativescript/ios": "~8.8.0",
|
"@nativescript/ios": "~8.8.0"
|
||||||
"@nativescript/tailwind": "^2.1.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1,7 @@
|
|||||||
|
.ns-root {
|
||||||
|
--base-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
background-color: var(--base-color);
|
||||||
|
}
|
||||||
@ -1,3 +1,7 @@
|
|||||||
import { Application } from '@nativescript/core';
|
import { Application } from '@nativescript/core';
|
||||||
|
import { localize } from '@nativescript/localize';
|
||||||
|
|
||||||
|
Application.setResources({ L: localize })
|
||||||
|
|
||||||
Application.run({ moduleName: 'app-root' });
|
Application.run({ moduleName: 'app-root' });
|
||||||
|
console.log(localize('app.name'));
|
||||||
13
apps/blakus-nativescript/src/i18n/en.json
Normal file
13
apps/blakus-nativescript/src/i18n/en.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"app.name": "Blakus",
|
||||||
|
"amenity": {
|
||||||
|
"bar": "Bar",
|
||||||
|
"biergarten": "Beer Garden",
|
||||||
|
"cafe": "Cafe",
|
||||||
|
"fast_food": "Fast Food",
|
||||||
|
"food_court": "Food Court",
|
||||||
|
"ice_cream": "Ice Cream",
|
||||||
|
"pub": "Pub",
|
||||||
|
"restaurant": "Restaurant"
|
||||||
|
}
|
||||||
|
}
|
||||||
13
apps/blakus-nativescript/src/i18n/lv.default.json
Normal file
13
apps/blakus-nativescript/src/i18n/lv.default.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"app.name": "Blakus",
|
||||||
|
"amenity": {
|
||||||
|
"bar": "Bārs",
|
||||||
|
"biergarten": "Biergarten",
|
||||||
|
"cafe": "Kafejnīca",
|
||||||
|
"fast_food": "Ātras uzkodas",
|
||||||
|
"food_court": "Ēdināšanas laukums",
|
||||||
|
"ice_cream": "Saldējums",
|
||||||
|
"pub": "Krogs",
|
||||||
|
"restaurant": "Restorāns"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
apps/blakus-nativescript/src/location.ts
Normal file
32
apps/blakus-nativescript/src/location.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import * as geolocation from '@nativescript/geolocation';
|
||||||
|
import { CoreTypes } from '@nativescript/core'
|
||||||
|
|
||||||
|
export class DeviceLocation {
|
||||||
|
static async getDeviceLocation() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Enable location services
|
||||||
|
await geolocation.enableLocationRequest(false, true);
|
||||||
|
|
||||||
|
const enabled = await geolocation.isEnabled();
|
||||||
|
|
||||||
|
console.log('what do we got?', enabled)
|
||||||
|
|
||||||
|
// Get the current location
|
||||||
|
const location = await geolocation.getCurrentLocation({
|
||||||
|
desiredAccuracy: CoreTypes.Accuracy.high,
|
||||||
|
maximumAge: 5000,
|
||||||
|
timeout: 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (location) {
|
||||||
|
console.log(`Latitude: ${location.latitude}, Longitude: ${location.longitude}`);
|
||||||
|
return location;
|
||||||
|
} else {
|
||||||
|
throw new Error('Could not get the location.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error obtaining location:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,22 @@
|
|||||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||||
<Page.actionBar>
|
<Page.actionBar>
|
||||||
<ActionBar title="My App" icon="" class="action-bar">
|
<ActionBar title="Blakus" icon="" class="action-bar">
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
</Page.actionBar>
|
</Page.actionBar>
|
||||||
<StackLayout class="p-20">
|
<StackLayout class="p-20">
|
||||||
<Label text="Tap the button" class="h1 text-center"/>
|
<Label text="Tap the button" class="h1 text-center"/>
|
||||||
<Button text="TAP" tap="{{ onTap }}" class="btn btn-primary btn-active"/>
|
<Button text="TAP" tap="{{ onTap }}" />
|
||||||
|
<Button text="Location" tap="{{ onLocationTap }}" />
|
||||||
<Label text="{{ message }}" class="h2 text-center" textWrap="true"/>
|
<Label text="{{ message }}" class="h2 text-center" textWrap="true"/>
|
||||||
|
<ListView items="{{ items }}" itemTap="{{ onItemTap }}">
|
||||||
|
<ListView.itemTemplate>
|
||||||
|
<!-- The item template can only have a single root element -->
|
||||||
|
<GridLayout padding="16" columns="20, *, *">
|
||||||
|
<ContentView width="20" height="20" borderRadius="20" backgroundColor="#65adf1" />
|
||||||
|
<Label text="{{ title }}" col="1" textWrap="true" marginLeft="8" />
|
||||||
|
<Label text="{{ L(`amenity.${amenity}`) }}" col="2" />
|
||||||
|
</GridLayout>
|
||||||
|
</ListView.itemTemplate>
|
||||||
|
</ListView>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@ -1,8 +1,53 @@
|
|||||||
import { Observable } from '@nativescript/core';
|
import { Observable, Http, type ItemEventData, ListView } from '@nativescript/core';
|
||||||
|
import { DeviceLocation } from './location';
|
||||||
|
import type { Location } from '@nativescript/geolocation';
|
||||||
|
import { localize } from '@nativescript/localize';
|
||||||
|
|
||||||
|
type ReverseGeocodeResult = {
|
||||||
|
valsts: string;
|
||||||
|
admin_vien: string;
|
||||||
|
terit_vien: string;
|
||||||
|
apdz_vieta: string;
|
||||||
|
iela: string;
|
||||||
|
maja: string;
|
||||||
|
index: string;
|
||||||
|
korpus: string;
|
||||||
|
vzd_id: string;
|
||||||
|
distance: number;
|
||||||
|
x: string;
|
||||||
|
y: string;
|
||||||
|
lon: number;
|
||||||
|
lat: number;
|
||||||
|
adrese: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlakusItem = {
|
||||||
|
title: string;
|
||||||
|
amenity: string;
|
||||||
|
tags: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type OverpassResult = {
|
||||||
|
version: number;
|
||||||
|
generator: string;
|
||||||
|
osm3s: Record<string, string>;
|
||||||
|
elements: {
|
||||||
|
type: string,
|
||||||
|
id: number,
|
||||||
|
tags: Record<string, string>;
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function aWait(timeout: number) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
export class HelloWorldModel extends Observable {
|
export class HelloWorldModel extends Observable {
|
||||||
private _counter: number;
|
private _counter: number;
|
||||||
private _message: string;
|
private _message: string;
|
||||||
|
private _items: BlakusItem[];
|
||||||
|
private _locationServiceBaseURL = 'https://api.kartes.lv/v3/KVDM_mwwKi/'
|
||||||
|
private _overpassBaseURL = 'https://overpass-api.de/api/';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -23,17 +68,115 @@ export class HelloWorldModel extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTap() {
|
get items(): BlakusItem[] {
|
||||||
this._counter--;
|
return this._items || [];
|
||||||
this.updateMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateMessage() {
|
set items(value: BlakusItem[]) {
|
||||||
|
if (this._items !== value) {
|
||||||
|
this._items = value;
|
||||||
|
this.notifyPropertyChange('items', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async reverseGeocode({latitude, longitude}: Location) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.set('lat', latitude.toString());
|
||||||
|
params.set('lon', longitude.toString());
|
||||||
|
|
||||||
|
this.message = [latitude, longitude].join(', ');
|
||||||
|
|
||||||
|
const url = new URL(`reverse_geocoding?${params}`, this._locationServiceBaseURL).toString();
|
||||||
|
const result = await Http.getJSON<ReverseGeocodeResult>(url);
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
overpassQuery(query: string) {
|
||||||
|
const url = new URL(`interpreter?data=${encodeURIComponent(query)}`, this._overpassBaseURL).toString();
|
||||||
|
console.log('overpass query', url)
|
||||||
|
return Http.getJSON<OverpassResult>(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOverpassAmenities({latitude, longitude}: Location) {
|
||||||
|
const radius = 1000; // meters
|
||||||
|
const query = `
|
||||||
|
[out:json][timeout:25];
|
||||||
|
node["amenity"](around:${radius}, ${latitude}, ${longitude});
|
||||||
|
out tags;
|
||||||
|
`;
|
||||||
|
const result = await this.overpassQuery(query);
|
||||||
|
console.log('yep');
|
||||||
|
console.log(Array.from(new Set(result.elements.map(el => el.tags['amenity']))));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOverpassInfo({latitude, longitude}: Location) {
|
||||||
|
|
||||||
|
const radius = 1000; // meters
|
||||||
|
const amenities = ['restaurant', 'cafe', 'bar', 'pub', 'biergarten', 'fast_food', 'food_court', 'ice_cream'];
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
[out:json];
|
||||||
|
node(around:${radius}, ${latitude}, ${longitude})["amenity"~"${amenities.join('|')}"];
|
||||||
|
out body;
|
||||||
|
>;
|
||||||
|
out skel qt;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await this.overpassQuery(query);
|
||||||
|
this.items = result.elements
|
||||||
|
.map(({ tags }) => ({ title: tags.name, amenity: tags.amenity, tags}))
|
||||||
|
.filter(i => amenities.includes(i.amenity)); // query returns some random results. need to look into this
|
||||||
|
|
||||||
|
console.log(localize('app.name'))
|
||||||
|
|
||||||
|
console.log(result.elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
async postalPolygons(country = 'LV', code: string, mode: 'isolate' | 'collect' | 'union' = 'union') {
|
||||||
|
await aWait(1000);
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (code.length === 4) params.set('search', `${country}-${code}`);
|
||||||
|
if (code.length == 2) params.set('groups', `${country}-${code}`)
|
||||||
|
params.set('union_mode', mode);
|
||||||
|
params.set('wgs84', '');
|
||||||
|
// params.set('wkt', '');
|
||||||
|
const url = new URL(`postal_codes?${params}`, this._locationServiceBaseURL).toString();
|
||||||
|
|
||||||
|
const result = await Http.getJSON(url);
|
||||||
|
console.log(url);
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async onLocationTap() {
|
||||||
|
const location = await DeviceLocation.getDeviceLocation();
|
||||||
|
await this.getOverpassInfo(location);
|
||||||
|
// await this.getOverpassAmenities(location);
|
||||||
|
// const { index } = await this.reverseGeocode(location);
|
||||||
|
// const [country, code] = index.split('-');
|
||||||
|
// await this.postalPolygons(country, code);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onTap() {
|
||||||
|
this._counter--;
|
||||||
|
|
||||||
if (this._counter <= 0) {
|
if (this._counter <= 0) {
|
||||||
this.message =
|
this.updateMessage('Hoorraaay! You unlocked the NativeScript clicker achievement!');
|
||||||
'Hoorraaay! You unlocked the NativeScript clicker achievement!';
|
|
||||||
} else {
|
} else {
|
||||||
this.message = `${this._counter} taps left`;
|
this.updateMessage(`${this._counter} taps left`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onItemTap(args: ItemEventData) {
|
||||||
|
const listView = args.object as ListView
|
||||||
|
console.log('Tapped item', listView.items[args.index])
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateMessage(message = "") {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: ['./src/**/*.{css,xml,html,vue,svelte,ts,tsx}'],
|
|
||||||
// use the .ns-dark class to control dark mode (applied by NativeScript) - since 'media' (default) is not supported.
|
|
||||||
darkMode: ['class', '.ns-dark'],
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
corePlugins: {
|
|
||||||
preflight: false, // disables browser-specific resets
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Loading…
x
Reference in New Issue
Block a user