Skip to content

Commit

Permalink
Update stats UI on app bar.
Browse files Browse the repository at this point in the history
- all grouped together
- all have same "working" spin progress bar
- location data removed from footer added to new menu
Update README. add pics and usage guide
Update to v 0.0.1j
  • Loading branch information
cwhelchel committed Mar 18, 2024
1 parent f609e49 commit 5622669
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 65 deletions.
127 changes: 97 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,114 @@
# pywebview-react-boilerplate
This is a simple boilerplate to help you start with _pywebview_ and React. It sets up the development environment, install dependencies, as well as provides scripts for building an executable. Stack is based on pywebview, React, SASS, Parcel bundler, pyinstaller (Windows/Linux) and py2app (macOS).
# Hunterlog

## Requirements
- Python 3
- Node
- virtualenv
*THIS IS NOT YOUR MAIN LOGGING PROGRAM!*

## Installation
This is a replacement for the excellent [potaplus](https://dwestbrook.net/projects/potaplus/) Chrome browser extension. If you have used that then this application
should be very familiar.

``` bash
npm run init
```
This application allows you to browse the current POTA spots, QSY your rig via
FLRIG, and log them to your logger through a remote ADIF message.

This will create a virtual environment, install pip and Node dependencies. Alternatively you can perform these steps manually.
![Screenshot of the goods](docs/img/main.png)

``` bash
npm install
pip install -r requirements.txt
```
## Usage

On Linux systems installation system makes educated guesses. If you run KDE, QT dependencies are installed, otherwise GTK is chosen. `apt` is used for installing GTK dependencies. In case you are running a non apt-based system, you will have to install GTK dependencies manually. See [installation](https://pywebview.flowrl.com/guide/installation.html) for details.
On Windows, run the executable in any folder.

## Usage
The very first thing you should notice is that the default configuration is for
W1AW. You probably aren't the ghost of Hiram Percy Maxim, so you should change
your callsign. Click the `CONFIGURATION` button next to the callsign and input
your callsign and your gridsquare.


### Configuration

Let's look at the configuration options.

![Configuration options](docs/img/config.png)

Default TX Power is used in logging. Put over legal limit if you want.

FLRIG Host IP and Port:

The app uses FLRIG to handle CAT control. These two values are the remote
endpoint of the FLRIG instance that's running. The default FLRIG port is 12345

The radio buttons are for the logger. Select Default or Log4om to send the basic
ADIF data to a remote logger. Select AClog if you use AcLog as it has to have
the data wrapped in a different command. (Default and Log4om do the same thing currently)

Remote ADIF Host and port:

The remote endpoint data to send logged QSOs. Should be running Log4om or AClog
or any other logger that accepts raw ADIF over UDP connections.

Click save to store the changes. Then click the refresh button on the main
screen to see your callsign and your configured Gravatar. You have a POTA
account right?

To launch the application.
### Stats

``` bash
npm run start
```
If you want to see your some nice stats like the POTAPlus addon, you need to
update your stats using the `STATS` menu. There are three options here.

To build an executable. The output binary will be produced in the `dist` directory.
![Stat Menu Buttons](docs/img/stats.png)

``` bash
npm run build
```
**STATISTICAL DATA SHOWN IN THIS APP IS NOT AUTHORITATIVE** The authoritative data
of record is your data in https://pota.app

To start a development server (only for testing frontend code).
#### PARK STATS
This is useful to show what parks you have hunted and how many times you've hunted
them.

``` bash
npm run dev
```
You must to visit [https://pota.app/#stats/](https://pota.app/#/user/stats) and use the Hunted Parks "Export CSV" button to download the `hunter_parks.csv` file.

Click the `PARK STATS` button, select your csv file, and wait for several minutes.
This operation takes a long time as park data must be downloaded and stored in
the local `spots.db` database.

This does take a long time, so there are export links at the bottom of the app
so this data can be backed up.

#### OP STATS
This is an import of an ADIF copy of your 'main' log file. Your QSOs should have
the ADIF fields set as so:
- SIG set to 'POTA'
- SIG_INFO set to the park reference
- COMMENT like the POTAPLUS comment ex: `[POTA K-4451 US-AL EM72el Tuskegee National Forest]`

The import will try it's best to match the park and will worst case parse the POTAPlus
comment. *This data is not used for Park hunt counts but only for Operator hunt counts.*

#### LOC STATS
Downloads and imports the locations data from the POTA website and stores them
locally. No hunter data is in this file but the meta-data about locations and
prefixes is used to tabulate the parks hunted within a location. Ie you have
worked 78/224 in US-GA.

### Logging QSOs

I'm tired of writing: Click a spot to load the QSO info into the top portion
of the screen. Click green frequency button to QSY with CAT control. Click
Log QSO after you've had the contact. The app will update stats and send the
QSO data (with any modifications you do to the input) to your main logger.

*It also will store a copy locally in hunter.adi as well as in the database.* This
is for your convenience.

## Files

Running the app will create the `spots.db` which is very important as it will
contain all your qsos, configuration settings and stats such as parks and
locations.

The file `index.log` is the application's log file. It is not the same as the
Javascript console that maybe seen when inspecting the webpage.


## Bug reporting

Please report _pywebview_ related bugs directly to [pywebview's repository](https://github.com/r0x0r/pywebview). This repository is only for the issues related to this boilerplate.
This app is currently under pre-release. Please report bugs here on Github
issues.


\- Cainan N9FZ
2 changes: 1 addition & 1 deletion build-windows.spec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ exe = EXE(pyz,
a.zipfiles,
a.datas,
[],
name='pywebview-react',
name='hunterlog',
debug=False,
bootloader_ignore_signals=False,
strip=False,
Expand Down
67 changes: 67 additions & 0 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Developer Notes

Hunterlog uses [pywebview](https://pywebview.flowrl.com/) to display a single
page web application and this project was started from their
[pywebview-react-boilerplate](https://github.com/r0x0r/pywebview-react-boilerplate)
project. Note: the parcel bundler version that it calls out had issues with the
map component I wanted to use so this uses a newer parcel version.

The web application frontend is built using React Typescript and the [MUI React](https://mui.com/) component library. It also uses leaflet and react-leaflet for
the mapping component and dayjs for datetime stuff.

The backend, is written in Python and has its dependencies called out in
`requirements.txt`. The big ones being: marshmallow, marshmallow-sqlalchemy,
SqlAlchemy, adif-io, and alembic.

Not listed there but worth noting is that this includes python rig CAT control
written for the [Augratin](https://github.com/mbridak/augratin) project with
some minor modifications.

For Linux, the GTK dependencies for pywebview need to be installed. Currently
this is tested on Ubuntu 22.04.4

## Dev Dependencies

Alembic is used to modify and track changes to the sqlite db schema for the main
database. The version is tracked in new databases when created but the developer
has to update the `db.py` script manually with the new Alembic version string.

Flake8 and autopep8 are used in vscode for python linting.

pyinstaller is used to package the source into an executable file.

## Requirements
- Python 3
- Node
- virtualenv

*The last one not so much, as the npm run init has been changed to use python -m venv*

## Installation

``` bash
npm run init
```

This will create a virtual environment, install pip and Node dependencies. Alternatively you can perform these steps manually.

``` bash
npm install
pip install -r requirements.txt
```

On Linux systems installation system makes educated guesses. If you run KDE, QT dependencies are installed, otherwise GTK is chosen. `apt` is used for installing GTK dependencies. In case you are running a non apt-based system, you will have to install GTK dependencies manually. See [installation](https://pywebview.flowrl.com/guide/installation.html) for details.

## Usage

To launch the application.

``` bash
npm run start
```

To build an executable. The output binary will be produced in the `dist` directory.

``` bash
npm run build
```
Binary file added docs/img/config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/main.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/stats.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
11 changes: 7 additions & 4 deletions src/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,14 @@ def launch_pota_window(self):
title='POTA APP', url='https://pota.app/#/user/stats')

def load_location_data(self):
logging.debug("downloading location data...")
locations = PotaApi.get_locations()
self.db.locations.load_location_data(locations)
# self.pw.evaluate_js
# (token, cookies) = self.get_id_token(self.pw)
# logging.debug(f"token: {token}")
result = {
'success': True,
'message': "downloaded location data successfully",
}
return json.dumps(result)

# self.pota.get_user_hunt(token, cookies)

Expand Down Expand Up @@ -301,7 +304,7 @@ def update_park_hunts_from_csv(self) -> str:
filename = webview.windows[0] \
.create_file_dialog(
webview.OPEN_DIALOG,
file_types=ft)
file_types=ft)
if not filename:
return json.dumps({'success': True, 'message': "user cancel"})

Expand Down
6 changes: 4 additions & 2 deletions src/components/AppMenu/AppMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { ImportAdif } from '../Stats/ImportAdif';
import { UserConfig } from '../../@types/Config';
import { ActivatorData } from '../../@types/ActivatorTypes';
import { Avatar, Tooltip } from '@mui/material';
import StatusMenu from './StatsMenu';
import StatsMenu from './StatsMenu';

export default function AppMenu() {

Expand Down Expand Up @@ -53,15 +55,15 @@ export default function AppMenu() {
{callsign}
</Typography>
<ConfigModal />
<UpdateStats />
<ImportAdif />
<StatsMenu />
<Tooltip title="Refresh">
<IconButton onClick={() => {
location.reload();
}}>
<RefreshIcon color='primary' />
</IconButton>
</Tooltip>

</Toolbar>
</AppBar>
</Box>
Expand Down
61 changes: 61 additions & 0 deletions src/components/AppMenu/StatsMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';

import { useAppContext } from '../AppContext';
import { UpdateStats } from '../Stats/UpdateStats';
import { ImportAdif } from '../Stats/ImportAdif';
import { Button, CircularProgress, Menu, MenuItem } from '@mui/material';
import { LocationStatsButton } from '../Stats/LocationStats';

export default function StatusMenu() {

const [isWorking, setIsWorking] = React.useState(false);
const { contextData, setData } = useAppContext();
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};


return (
<div>
<Button
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
>
Stats
{isWorking && (
<div style={{ 'display': 'flex' }}>
<CircularProgress />
</div>
)}
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<MenuItem >
<UpdateStats setIsWorking={setIsWorking} />
</MenuItem>
<MenuItem >
<ImportAdif setIsWorking={setIsWorking} />
</MenuItem>
<MenuItem >
<LocationStatsButton setIsWorking={setIsWorking} />
</MenuItem>
</Menu>
</div>
);
}
11 changes: 0 additions & 11 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ export default function Footer() {
}
}

function handleLoadLocData() {
if (window.pywebview) {
window.pywebview.api.load_location_data();
}
}

function handleExportParkData() {
if (window.pywebview) {
window.pywebview.api.export_park_data();
Expand All @@ -52,11 +46,6 @@ export default function Footer() {
<Link href="#" onClick={() => {handleOnClick()}} ml={1} mr={1}>
Export Logged QSOs
</Link>
<Tooltip title="Load POTA locations for Stats">
<Link href="#" onClick={() => {handleLoadLocData()}} ml={1} mr={1}>
Load Location Data
</Link>
</Tooltip>
<Link href="#" onClick={() => {handleExportParkData()}} ml={1} mr={1}>
Export Park Info
</Link>
Expand Down
Loading

0 comments on commit 5622669

Please sign in to comment.