├── README.md ├── dart ├── char_freq_hist │ ├── char_freq_hist.dart │ └── ulysses.txt ├── database_sqlite │ ├── database_helper.dart │ ├── esempio_screen_con_helper.png │ ├── main.dart │ ├── main_con_helper.dart │ └── utente.dart └── snippets │ ├── named-parameter.dart │ ├── optional-parameter.dart │ └── tuple.dart ├── esercitazioni ├── esercitazione_10032025-2.js ├── esercitazione_10032025-3.js ├── esercitazione_10032025.js ├── esercitazione_12032025-2.js ├── esercitazione_12032025-3.js ├── esercitazione_12032025-4.js └── esercitazione_12032025.js ├── flutter ├── 05052025.dart └── snippets │ ├── 0-senza-materialapp.dart │ ├── 1-con-materialapp.dart │ ├── 10-elevatedbutton.dart │ ├── 13-counter.dart │ ├── 14-counter-complex.dart │ ├── 15-listview.dart │ ├── 16-listview-horizontal.dart │ ├── 17-gridview.dart │ ├── 18-gridview-horizontal.dart │ ├── 19-heterogeneous-list.dart │ ├── 2-con-materialapp-e-scaffold.dart │ ├── 20-add-to-list.dart │ ├── 21-lista-stile.dart │ ├── 22-container-tema.dart │ ├── 23-theme-child.dart │ ├── 24-theme-override.dart │ ├── 25-margin-padding.dart │ ├── 26-textfield-textformfield.dart │ ├── 27-textfield-controller.dart │ ├── 28-listen-to-change-textfield.dart │ ├── 29-form-validation.dart │ ├── 3-app-e-appbar.dart │ ├── 30-load-json.dart │ ├── 31-navigation-back-and-forth.dart │ ├── 32-tabs.dart │ ├── 33-todo-descr.dart │ ├── 34-return-data.dart │ ├── 4-creare-un-widget.dart │ ├── 5-app-base-material-components.dart │ ├── 6-column-row.dart │ ├── 7-container.dart │ ├── 8-stack.dart │ └── 9-appbar.dart ├── js ├── README.md ├── char_freq_hist │ ├── hist.js │ └── ulysses.txt ├── hello.js └── javascript-recap-nosolutions.md ├── pwa ├── offline_serviceworker │ ├── .DS_Store │ ├── css │ │ └── style.css │ ├── index.html │ ├── js │ │ └── app.js │ └── serviceWorker.js └── temperature_converter │ ├── converter.css │ ├── convertitore.js │ ├── icon512.png │ ├── index.html │ ├── manifest.json │ └── serviceworker.js └── react-native ├── database_sqlite └── App.tsx ├── dependency-expo.md ├── navigation ├── stack-navigation-0.tsx ├── stack-navigation-1.tsx ├── stack-navigation-10.tsx ├── stack-navigation-11.tsx ├── stack-navigation-2.tsx ├── stack-navigation-3.tsx ├── stack-navigation-4.tsx ├── stack-navigation-5.tsx ├── stack-navigation-6.tsx ├── stack-navigation-7.tsx ├── stack-navigation-8.tsx └── stack-navigation-9.tsx ├── snippets ├── basic-image-0.tsx ├── basic-image-1.tsx ├── basic-image-2.tsx ├── basic-scrollview-0.tsx ├── basic-text-0.tsx ├── basic-textinput-0.tsx ├── basic-textinput-1.tsx ├── basic-view-0.tsx ├── extra-activityindicator-0.tsx ├── extra-alert-0.tsx ├── extra-modal-0.tsx ├── extra-statusbar-0.tsx ├── listview-flatlist-0.tsx ├── listview-sectionlist-0.tsx ├── logo_unisa.png ├── propswithchildren.tsx ├── ui-button-0.tsx └── ui-switch-0.tsx ├── sorgenti_02042025 ├── esempio_2_flex.tsx ├── esempio_sectionlist.tsx └── todoapp_incompleta.tsx ├── sorgenti_16032025 ├── source_1.js ├── source_2.js ├── source_3.js └── source_4.js └── sorgenti_31032025 ├── esempi-useState.js └── todo-app_incompleta.js /README.md: -------------------------------------------------------------------------------- 1 | # Mobile Programming 2 | 3 | Repository del corso **Mobile Programming** (A.A. 2024/25, CdS Ingegneria Informatica, Università degli Studi di Salerno). 4 | 5 | ## Schedule 6 | 7 | - Lunedì 11:30 – 13:30, Aula delle Lauree; 8 | - Mercoledì 10:30 – 13:30, Aula H. 9 | 10 | ## Contatti 11 | 12 | Francesco Cauteruccio, Ph.D. – Università degli Studi di Salerno, [fcauteruccio@unisa.it](fcauteruccio@unisa.it) 13 | -------------------------------------------------------------------------------- /dart/char_freq_hist/char_freq_hist.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | // Questa classe rappresenta il nostro istrogramma 5 | class Histogram { 6 | // Mappa carattere -> frequenza 7 | Map char2freq = {}; 8 | // Caratteri totali letti 9 | int n = 0; 10 | 11 | // Parserizza una stringa proveniente da standard input 12 | void parseLine(String line) { 13 | // Rimuoviamo tutti gli spazi tramite un'espressione regolare 14 | var cleanLine = line.replaceAll(RegExp(r'\s'), ''); 15 | 16 | // Rendiamo i caratteri nella stringa maiuscoli e iteriamo su essi 17 | for (final char in cleanLine.toUpperCase().split('')) { 18 | // Map.update() aggiorna il valore relativo alla chiave scelta 19 | // la prima funzione aggiorna il valore basandosi su quello corrente 20 | // se la chiave non esiste, aggiunge un nuovo valore tramite la funzione ifAbsent 21 | char2freq.update(char, (value) => value + 1, ifAbsent: () => 1); 22 | n += 1; 23 | } 24 | } 25 | 26 | // Metodo privato, serve a creare la stringa rappresentante una barra 27 | // dell'istogramma 28 | String _createBar((String, double) pair) { 29 | return '${pair.$1}: ${"#" * pair.$2.round()} ${pair.$2.toStringAsFixed(2)}'; 30 | } 31 | 32 | // Override del metodo .toString(), che verrà invocato quando 33 | // proveremo a fare un print() dell'istanza di Histogram 34 | @override 35 | String toString() { 36 | // Map.entries() restituisce un iteratore sugli 37 | // elementi (chiave, valore) della mappa 38 | var entries = char2freq.entries.toList(); 39 | 40 | // Il sort ha lo stesso behavior come in Java e JS 41 | entries.sort((a, b) => a.value == b.value 42 | ? b.key.compareTo(a.key) 43 | : b.value.compareTo(a.value)); 44 | 45 | // map modifica i valori delle frequenze in percentuali 46 | // il where è l'equivalente del filter, e mantiene solo quegli elementi con 47 | // percentuale maggiore o uguale a 1 48 | var finalValues = entries 49 | .map((entry) => (entry.key, entry.value / n * 100)) 50 | .where((pair) => pair.$2 >= 1) 51 | .toList(); 52 | 53 | // map applica la funzione _createBar ad ogni elemento 54 | // di finalValues, così da creare una String per ognuno di essi 55 | return finalValues.map(_createBar).join('\n'); 56 | } 57 | } 58 | 59 | void main() { 60 | var h = Histogram(); 61 | 62 | // stdin è lo stream per lo standard input 63 | // la prima trasformazione dello stream riguarda la codifica (in utf8) 64 | // la seconda splitta per ogni linea 65 | // listen() "abbona" un listener allo stream 66 | // - quando arriva un evento line, che è una String, la parserizziamo 67 | // - onDone viene invocata quando lo stream termina (es, EOF) 68 | stdin.transform(utf8.decoder).transform(const LineSplitter()).listen((line) { 69 | h.parseLine(line); 70 | }, onDone: () => print(h)); 71 | } 72 | -------------------------------------------------------------------------------- /dart/database_sqlite/database_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite/sqflite.dart'; 2 | import 'package:path/path.dart'; 3 | 4 | class DatabaseHelper { 5 | DatabaseHelper._privateConstructor(); 6 | static final DatabaseHelper instance = DatabaseHelper._privateConstructor(); 7 | 8 | static Database? _database; 9 | Future get database async => _database ??= await _initDatabase(); 10 | 11 | Future _initDatabase() async { 12 | return openDatabase( 13 | join(await getDatabasesPath(), 'mio_database.db'), 14 | onCreate: (db, version) { 15 | return db.execute( 16 | 'CREATE TABLE utenti(matricola INTEGER PRIMARY KEY, nome TEXT, eta INTEGER, ruolo TEXT)', 17 | ); 18 | }, 19 | version: 1, 20 | ); 21 | } 22 | 23 | Future insertUtente(Utente utente) async { 24 | final db = await database; 25 | await db.insert( 26 | 'utenti', 27 | utente.toMap(), 28 | conflictAlgorithm: ConflictAlgorithm.replace, 29 | ); 30 | } 31 | 32 | // Tutti gli altri metodi 33 | // ... 34 | } 35 | -------------------------------------------------------------------------------- /dart/database_sqlite/esempio_screen_con_helper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finalfire/mobprog-unisa/7a15135beed09cbefac3576587139911cbf5fd66/dart/database_sqlite/esempio_screen_con_helper.png -------------------------------------------------------------------------------- /dart/database_sqlite/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:path/path.dart'; 3 | import 'package:sqflite/sqflite.dart'; 4 | import 'utente.dart'; 5 | 6 | void main() { 7 | runApp(MyApp()); 8 | } 9 | 10 | class MyApp extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | return MaterialApp( 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | @override 21 | _HomePageState createState() => _HomePageState(); 22 | } 23 | 24 | class _HomePageState extends State { 25 | Database? database; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | initializeDb(); 31 | } 32 | 33 | Future initializeDb() async { 34 | database = await openDatabase( 35 | join(await getDatabasesPath(), 'mio_database.db'), 36 | onCreate: (db, version) { 37 | return db.execute( 38 | 'CREATE TABLE utenti(matricola INTEGER PRIMARY KEY, nome TEXT, eta INTEGER, ruolo TEXT)', 39 | ); 40 | }, 41 | version: 1, 42 | ); 43 | } 44 | 45 | Future insertUtente(Utente utente) async { 46 | await database!.insert( 47 | 'utenti', 48 | utente.toMap(), 49 | conflictAlgorithm: ConflictAlgorithm.replace, 50 | ); 51 | } 52 | 53 | void insertDummyUtente(BuildContext context) { 54 | Utente newUtente = Utente( 55 | matricola: 0, nome: "Pluto", eta: 25, ruolo: "Software Engineer"); 56 | insertUtente(newUtente).then((_) { 57 | ScaffoldMessenger.of(context).showSnackBar( 58 | SnackBar(content: Text('Utente Pluto inserito con successo!'))); 59 | }); 60 | } 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Scaffold( 65 | appBar: AppBar( 66 | title: const Text('SQLite Example'), 67 | ), 68 | body: Center( 69 | child: ElevatedButton( 70 | onPressed: () => insertDummyUtente(context), 71 | child: const Text('Inserisci Pluto'), 72 | ), 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /dart/database_sqlite/main_con_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'database_helper.dart'; 3 | import 'utente.dart'; 4 | 5 | void main() { 6 | runApp(const MyApp()); 7 | } 8 | 9 | class MyApp extends StatelessWidget { 10 | const MyApp({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return const MaterialApp( 15 | home: UtentiScreen(), 16 | ); 17 | } 18 | } 19 | 20 | class UtentiScreen extends StatefulWidget { 21 | const UtentiScreen({super.key}); 22 | 23 | @override 24 | State createState() => _UtentiScreenState(); 25 | } 26 | 27 | class _UtentiScreenState extends State { 28 | final TextEditingController _matricolaController = TextEditingController(); 29 | final TextEditingController _nomeController = TextEditingController(); 30 | final TextEditingController _etaController = TextEditingController(); 31 | final TextEditingController _ruoloController = TextEditingController(); 32 | List _utenti = []; 33 | 34 | @override 35 | void initState() { 36 | super.initState(); 37 | _fetchUtenti(); 38 | } 39 | 40 | Future _fetchUtenti() async { 41 | final db = DatabaseHelper.instance; 42 | final List> maps = 43 | await db.database.then((db) => db.query('utenti')); 44 | 45 | setState(() { 46 | _utenti = List.generate(maps.length, (i) { 47 | final matricola = maps[i]['matricola']; 48 | final nome = maps[i]['nome']; 49 | final eta = maps[i]['eta']; 50 | final ruolo = maps[i]['ruolo']; 51 | return Utente( 52 | matricola: matricola as int, 53 | nome: nome as String, 54 | eta: eta as int, 55 | ruolo: ruolo as String); 56 | }); 57 | }); 58 | } 59 | 60 | Future _addUtente() async { 61 | final matricola = int.parse(_matricolaController.text); 62 | final nome = _nomeController.text; 63 | final eta = int.parse(_etaController.text); 64 | final ruolo = _ruoloController.text; 65 | 66 | final utente = 67 | Utente(matricola: matricola, nome: nome, eta: eta, ruolo: ruolo); 68 | await DatabaseHelper.instance.insertUtente(utente); 69 | _fetchUtenti(); 70 | 71 | _matricolaController.clear(); 72 | _nomeController.clear(); 73 | _etaController.clear(); 74 | _ruoloController.clear(); 75 | } 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | return Scaffold( 80 | appBar: AppBar( 81 | title: Text('Utenti'), 82 | ), 83 | body: Column( 84 | children: [ 85 | TextField( 86 | controller: _matricolaController, 87 | decoration: InputDecoration(labelText: 'Matricola'), 88 | ), 89 | TextField( 90 | controller: _nomeController, 91 | decoration: InputDecoration(labelText: 'Nome'), 92 | ), 93 | TextField( 94 | controller: _etaController, 95 | decoration: InputDecoration(labelText: 'Età'), 96 | keyboardType: TextInputType.number, 97 | ), 98 | TextField( 99 | controller: _ruoloController, 100 | decoration: InputDecoration(labelText: 'Ruolo'), 101 | ), 102 | ElevatedButton( 103 | onPressed: _addUtente, 104 | child: Text('Aggiungi Utente'), 105 | ), 106 | Expanded( 107 | child: ListView.builder( 108 | itemCount: _utenti.length, 109 | itemBuilder: (context, index) { 110 | final utente = _utenti[index]; 111 | return ListTile( 112 | title: Text(utente.nome), 113 | subtitle: Text( 114 | 'matricola ${utente.matricola}, ${utente.eta} anni, ${utente.ruolo}'), 115 | ); 116 | }, 117 | ), 118 | ), 119 | ], 120 | ), 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /dart/database_sqlite/utente.dart: -------------------------------------------------------------------------------- 1 | class Utente { 2 | final int matricola; 3 | final String nome; 4 | final int eta; 5 | final String ruolo; 6 | 7 | const Utente( 8 | {required this.matricola, 9 | required this.nome, 10 | required this.eta, 11 | required this.ruolo}); 12 | 13 | // Converte un Utente in una Map; le chiavi sono le colonne 14 | // della tabella `utenti` nel database 15 | Map toMap() { 16 | return {'matricola': matricola, 'nome': nome, 'eta': eta, 'ruolo': ruolo}; 17 | } 18 | 19 | @override 20 | String toString() { 21 | return 'Utente{matricola: $matricola, nome: $nome, eta: $eta, ruolo: $ruolo}'; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dart/snippets/named-parameter.dart: -------------------------------------------------------------------------------- 1 | // altro è un named parameter; è detto named 2 | // perché all'invocazione della funzione, il suo 3 | // valore effettivo lo indico tramite il nome del 4 | // parametro stesso 5 | // opt è un parametro che potrei anche non passare (opzionale) 6 | // per indicare questo uso il ? 7 | // ciao è un named parameter con valore di default pari a 5 8 | // se non passiamo ciao, avrò sempre e comunque il suo valore pari a 5 9 | int sommaTre(int a, int b, {required int altro, int ciao = 5, int? opt}) { 10 | if (opt == null) { 11 | return a + b + altro + ciao; 12 | } 13 | return a + b + altro + ciao + opt; 14 | } 15 | 16 | void main() { 17 | int risultato = sommaTre(10, 20, ciao: 20, altro: 12); 18 | print(risultato); 19 | } 20 | -------------------------------------------------------------------------------- /dart/snippets/optional-parameter.dart: -------------------------------------------------------------------------------- 1 | // la funzione hello prende in input tre valori 2 | // (1) nome -- parametro obbligatorio 3 | // (2) età -- parametro posizionale opzionale 4 | // (3) professione -- parametro posizionale opzionale 5 | // stampa (1) se gli altri non sono presenti 6 | String hello(String nome, [int? eta = 27, String? professione]) { 7 | var s = 'Ciao, ${nome}!'; 8 | if (eta != null) { 9 | s += '\nHai ${eta} anni!'; 10 | } 11 | if (professione != null) { 12 | s += '\nE fai il ${professione}'; 13 | } 14 | return s; 15 | } 16 | 17 | void main() { 18 | print(hello('Fra', 'Studente')); 19 | } 20 | -------------------------------------------------------------------------------- /dart/snippets/tuple.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | var tupla = (42, secondoInt: 24, 'Hello'); 3 | 4 | print(tupla.$1); 5 | print(tupla.secondoInt); 6 | print(tupla.$2); 7 | 8 | var f = 42; 9 | print('Ciao, f = ${f + 27}'); 10 | } 11 | -------------------------------------------------------------------------------- /esercitazioni/esercitazione_10032025-2.js: -------------------------------------------------------------------------------- 1 | let punto = { 2 | x: 10, 3 | y: 11 4 | }; 5 | 6 | // aggiungere un metodo a questo oggetto punto 7 | punto.somma = function() { 8 | return this.x + this.y; 9 | } 10 | // punto.somma = () => this.x + this.y; 11 | 12 | console.log(punto); 13 | console.log(punto.somma()); -------------------------------------------------------------------------------- /esercitazioni/esercitazione_10032025-3.js: -------------------------------------------------------------------------------- 1 | /*### Esercizio 4: Verifica della Presenza di una Proprietà 2 | Dichiarare un oggetto `phone` con le proprietà `brand` e `model`. Verifica se la proprietà `price` esiste.*/ 3 | 4 | // checkField(f,o) restituisce true se il campo f è presente nell'oggetto o 5 | function checkField(f,o) { 6 | if (o[f] !== undefined) 7 | return true; 8 | return false; 9 | } 10 | 11 | let phone = { 12 | brand: "Apple", 13 | model: "iPhone 12", 14 | space: "256 GB" 15 | }; 16 | 17 | let fields = ['price', 'memory', 'space']; 18 | for (let field of fields) { 19 | if (checkField(field, phone)) 20 | console.log("Il campo " + field + " è presente nell'oggetto phone con valore" + phone[field]) 21 | else 22 | console.log("Il campo " + field + " NON è presente nell'oggetto phone.") 23 | } -------------------------------------------------------------------------------- /esercitazioni/esercitazione_10032025.js: -------------------------------------------------------------------------------- 1 | // in JS le funzioni sono first-class citizen 2 | // che le funzioni possono essere considerate dei "valori" 3 | function sum(a, b) { 4 | return a + b; 5 | } 6 | let sumAr = (a,b) => a + b; 7 | 8 | let printAndSum = (a,b) => { 9 | console.log("a = " + a + " b = " + b); 10 | return a + b; 11 | } 12 | 13 | let pippo = sum; 14 | console.log(pippo(4,5)); // 9 15 | let one = function() { return 1; } 16 | console.log(sum(one(), 4)); // 5 17 | 18 | 19 | 20 | 21 | 22 | 23 | let wrapper = function(valore, f) { 24 | return f(valore); 25 | } 26 | 27 | let addOne = function(x) { return x + 1; } 28 | let addOneAr = x => x + 1; 29 | let risultato = wrapper(27, addOne); 30 | console.log(risultato); -------------------------------------------------------------------------------- /esercitazioni/esercitazione_12032025-2.js: -------------------------------------------------------------------------------- 1 | /*Esercizio 1: Passare una Funzione come Argomento 2 | Scrivere una funzione execute che prende una funzione e un valore e restituisce il risultato della funzione applicata al valore.*/ 3 | // let execute = (f,a) => { f(a) }; 4 | // qui posso passare f come parametro perché in JS le funzioni sono 5 | // considerate first-class citizen (quindi sono semplici valori) 6 | let execute = (f,a) => { 7 | return f(a); 8 | } 9 | 10 | function doppio(a) { 11 | return 2 * a; 12 | } 13 | 14 | let risultato1 = execute(doppio, 21); 15 | let risultato2 = execute(doppio, 13); 16 | console.log(risultato1); 17 | console.log(risultato2); 18 | 19 | /*Esercizio 2: Funzione di Callback 20 | Scrivere una funzione repeatAction che accetta un'azione (funzione) e la esegue tre volte.*/ 21 | function repeatAction(f, a) { 22 | f(a); 23 | f(a); 24 | f(a); 25 | } 26 | 27 | // questa arrow function è anche una funzione anonima 28 | repeatAction((x) => { console.log(x); }, "ciaooo"); 29 | 30 | let notAnonymous = () => { console.log("Ciao"); } 31 | repeatAction(notAnonymous); 32 | 33 | let stampaValore = function(valore) { 34 | console.log(valore); 35 | } 36 | repeatAction(stampaValore, "blablalba"); -------------------------------------------------------------------------------- /esercitazioni/esercitazione_12032025-3.js: -------------------------------------------------------------------------------- 1 | let f = () => { console.log("Ciao!!"); }; 2 | setTimeout(f, 5000); 3 | -------------------------------------------------------------------------------- /esercitazioni/esercitazione_12032025-4.js: -------------------------------------------------------------------------------- 1 | // scrivere una funzione che prenda una stringa s e analizzi la 2 | // frequenza dei simboli all'interno di s; la funzione deve restituire 3 | // un oggetto i cui campi sono tutti i simboli presenti in s e il valore di un campo 4 | // è quante volte appare quel simbolo in s 5 | function f(s) { 6 | let frequency_map = {}; 7 | // scorro => ciclo => itero su ogni carattere di s (stringa ~= array) 8 | // se ho un carattere c: c sta dentro la frequencymap? se sì => aggiungo 1 al suo valore 9 | // step 1: iterare su s 10 | for (let i = 0; i < s.length; i++) { 11 | // step 2: mi prendo il carattere ad indice i, e controllo se esso appartiene già alla frequency_map 12 | let character = s[i]; 13 | if (frequency_map[character] !== undefined) { 14 | // questo indica che character l'ho già incontrato durante l'iterazione 15 | // su s; ergo, character ha una frequenza maggiore di 0 16 | frequency_map[character] += 1; 17 | } else { 18 | // se sono qui, prima non ho incontrato character e quindi ora posso dire 19 | // che ha almeno una occorrenza 20 | frequency_map[character] = 1; 21 | } 22 | } 23 | 24 | return frequency_map; 25 | } 26 | 27 | // fm è la nostra frequency map 28 | function graph(fm) { 29 | // step 0.1: mi creo un array con tutti i campi (caratteri) che stanno 30 | // nella frequency map 31 | let character_array = []; 32 | for (const character in fm) 33 | character_array.push(character); 34 | // step 0.2: faccio un sort di questo array basato 35 | // sul valore che un character ha in fm 36 | // in sort posso anche passare una funzione anonima che prende in input due valori 37 | // (che sono due valori contigui nell'array originale) e indica come ordinarli 38 | character_array.sort((x,y) => { 39 | // se i due caratteri hanno lo stesso valore in fm 40 | if (fm[x] === fm[y]) { 41 | if (x < y) return -1; 42 | return 1; 43 | } 44 | 45 | if (fm[x] <= fm[y]) 46 | return 1; 47 | return -1; 48 | }); 49 | 50 | // step 1: itero su tutti i caratteri della frequency map 51 | //for (const character in fm) { 52 | for (let character of character_array) { 53 | let frequency = fm[character]; 54 | // step 2: creo una stringa che contiene tanti # quanto vale fm[character] 55 | let count_str = ""; 56 | for (let i = 0; i < frequency; i++) 57 | count_str += "#"; 58 | // step 3: scrivi su standard output la rappresentazione completa 59 | console.log(character + ": " + count_str + " (" + frequency + ")"); 60 | } 61 | } 62 | 63 | let pippo = f("Ciao siamo dei programmatori eccellenti!"); 64 | graph(pippo); -------------------------------------------------------------------------------- /esercitazioni/esercitazione_12032025.js: -------------------------------------------------------------------------------- 1 | /* Esercizio 1: Accesso agli Elementi 2 | Dichiarare un array colors contenente i valori "red", "green" e "blue". Stampa il primo e l’ultimo elemento.*/ 3 | let colors = ["red", "green", "blue"]; 4 | console.log(colors); 5 | console.log(colors[0]); // gli array sono zero-indexed (0...n-1) 6 | let n = colors.length; // la size/lunghezza di questo array 7 | console.log(colors[n - 1]); 8 | console.log(colors[n]); 9 | console.log(colors[1000000]); 10 | 11 | let f = (x) => { x + 1 } // return x+1; 12 | 13 | /*Esercizio 2: Aggiunta e Rimozione di Elementi 14 | Dichiarare un array fruits e aggiungi "apple" e "banana". Rimuovi il primo elemento.*/ 15 | let fruits = ["strawberry"]; 16 | console.log("Array: " + fruits) // ["strawberry"] 17 | fruits[fruits.length] = "apple"; 18 | console.log("Array: " + fruits) // ["strawberry", "apple"] 19 | fruits[2] = "banana"; 20 | console.log("Array: " + fruits) // ["strawberry", "apple", "banana"] 21 | fruits.push("lemon"); 22 | console.log("Array: " + fruits) // ["strawberry", "apple", "banana", "lemon"] 23 | //fruits.push(["pineapple", "orange"]) // aggiunge all'array ["pineapple", "orange"] (un solo valore) 24 | fruits.push("pineapple", "orange") 25 | 26 | for (let i = 0; i < fruits.length; i++) 27 | console.log("Valore ad indice " + i + " = " + fruits[i]); 28 | 29 | //fruits.push("pineapple", "orange") // aggiunre all'array prima "pineapple", e poi "orange" (due valori) 30 | //console.log("Array: " + fruits) // ["strawberry", "apple", "banana", "lemon", "pineapple", "orange"] 31 | //fruits.pop(); 32 | //console.log("Array: " + fruits) -------------------------------------------------------------------------------- /flutter/05052025.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp(title: 'Aggiungi alla lista', home: MyHomePage()); 11 | } 12 | } 13 | 14 | class MyHomePage extends StatefulWidget { 15 | @override 16 | _MyHomePageState createState() => _MyHomePageState(); 17 | } 18 | 19 | class _MyHomePageState extends State { 20 | // datasource 21 | final List _items = ['Pippo']; 22 | 23 | void _addItem() { 24 | // setState modifica lo stato corrente del widget 25 | // prende in input una funzione anonima 26 | // che si occupa di implementare la logica 27 | // della modifica dello stato 28 | setState(() { 29 | int nextNum = _items.length + 1; 30 | _items.add('Pluto $nextNum'); 31 | }); 32 | // quando setState termina, Flutter viene 33 | // notificato del fatto che c'è stato un cambiamento 34 | // questo triggera un nuovo rendering 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Scaffold( 40 | appBar: AppBar(title: Text('La mia lista')), 41 | // il costruttore builder accetta 42 | // due parametri: 43 | // - itemCount: quanti valori ho dentro il 44 | // datasource su cui costruirò 45 | // la lista 46 | // - itemBuilder: è una funzione anonima 47 | // che accetta due parametri, context 48 | // e index; context serve a rifersi 49 | // ai widget padri; 50 | // index indica l'i-esimo valore 51 | // della lista (partendo da 0) 52 | // itemBuilder viene invocato per ogni 53 | // valore del datasource 54 | body: ListView.builder( 55 | itemCount: _items.length, 56 | // itemBuilder dice come deve essere 57 | // il widget che rappresenta un singolo 58 | // item della ListView 59 | itemBuilder: (context, index) { 60 | return ListTile(title: Text(_items[index])); 61 | }, 62 | ), 63 | floatingActionButton: FloatingActionButton( 64 | // se premuto, invoca _addItem 65 | onPressed: _addItem, 66 | tooltip: 'Tocca per aggiungere', 67 | child: Icon(Icons.add), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /flutter/snippets/0-senza-materialapp.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Center( 13 | child: Text('Hello, World!', textDirection: TextDirection.ltr)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /flutter/snippets/1-con-materialapp.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | // Il testo si vede in modo differente 13 | return MaterialApp( 14 | title: 'La mia app', 15 | home: const Center(child: Text("Hello, world!")), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /flutter/snippets/10-elevatedbutton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Home extends StatelessWidget { 4 | const Home({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ 10 | ElevatedButton(onPressed: () {}, child: const Text("Toccami!")), 11 | SizedBox(height: 12), 12 | ElevatedButton(onPressed: null, child: const Text("Disabilitato")), 13 | ])); 14 | } 15 | } 16 | 17 | void main() { 18 | runApp( 19 | const MaterialApp( 20 | title: 'Material Components App', 21 | home: Scaffold(body: Home()), 22 | ), 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /flutter/snippets/13-counter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Counter extends StatefulWidget { 4 | // Questa classe rappresenta la configurazione dello stato. 5 | // Memorizza il valore fornito dal genitore (nessuno in questo caso) 6 | // utilizzato dal metodo build della classe State. 7 | // Anche in uno StatefulWidget, i campi sono sempre final. 8 | 9 | // Costruttore 10 | // key è un identificativo speciale che viene utilizzato nei Widget 11 | // ed è utilizzato per controllare la posizione del Widget nel widget tree. 12 | const Counter({super.key}); 13 | 14 | // createState() permette di collegare lo StatefulWidget al suo State 15 | // associato. In questo caso, lo stato è di tipo State, e 16 | // lo inizializziamo con una istanza di _CounterState() 17 | @override 18 | State createState() => _CounterState(); 19 | } 20 | 21 | class _CounterState extends State { 22 | // Valore dello stato 23 | int _counter = 0; 24 | 25 | void _increment() { 26 | setState(() { 27 | // Questa invocazione a setState riferisce a 28 | // Flutter che c'è stato un cambiamento nello State; 29 | // questo fa sì che il metodo build venga reinvocato 30 | // così che il rendering possa riportare il valore dello stato 31 | // aggiornato. Se cambiamo solo il valore, senza passare tramite setState, 32 | // il metodo build non verrà invocato e il rendering non cambierà. 33 | _counter++; 34 | }); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | // build() viene reinvocato ogni volta che si chiama setState. 40 | // Il metodo build è ottimizzato affinché tutto ciò 41 | // che contiene venga renderizzato in modo efficiente 42 | // (in tempo al più lineare nel numero dei widget contenuti). 43 | 44 | return Row( 45 | mainAxisAlignment: MainAxisAlignment.center, 46 | children: [ 47 | ElevatedButton( 48 | onPressed: _increment, 49 | child: const Text('Aggiungi'), 50 | ), 51 | const SizedBox(width: 16), 52 | Text('Conteggio: $_counter'), 53 | ], 54 | ); 55 | } 56 | } 57 | 58 | void main() { 59 | runApp( 60 | const MaterialApp( 61 | home: Scaffold( 62 | body: Center( 63 | child: Counter(), 64 | ), 65 | ), 66 | ), 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /flutter/snippets/14-counter-complex.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CounterDisplay extends StatelessWidget { 4 | // Questo Widget si occupa della presentazione 5 | // del valore dello stato, tramite un Text. 6 | // Il valore dello stato non è contenuto 7 | // in questo StatelessWidget ma viene ricevuto 8 | // come parametro (count) 9 | const CounterDisplay({required this.count, super.key}); 10 | 11 | final int count; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Text('Conteggio: $count'); 16 | } 17 | } 18 | 19 | class CounterIncrementor extends StatelessWidget { 20 | // Questo Widget si occupa di fornire il 21 | // componente di UI per modificare lo stato. 22 | // Nota come non effettua la modifica dello stato in sé, 23 | // ma riceve una VoidCallback (una funzione anonima che non restituisce 24 | // alcunché) che si occuperà di modificare lo stato. 25 | // Questa funzione è parte di uno StatefulWidget (Counter) che contiene 26 | // lo stato e si occupa della sua modifica. 27 | const CounterIncrementor({required this.onPressed, super.key}); 28 | 29 | final VoidCallback onPressed; 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return ElevatedButton( 34 | // Qui colleghiamo la VoidCallback 35 | onPressed: onPressed, 36 | child: const Text('Aggiungi'), 37 | ); 38 | } 39 | } 40 | 41 | class Counter extends StatefulWidget { 42 | // Lo StatefulWidget che mantiene lo stato. 43 | const Counter({super.key}); 44 | 45 | @override 46 | State createState() => _CounterState(); 47 | } 48 | 49 | class _CounterState extends State { 50 | // La classe rappresentante lo State vero e proprio 51 | int _counter = 0; 52 | 53 | void _increment() { 54 | setState(() { 55 | ++_counter; 56 | }); 57 | } 58 | 59 | // Il metodo build qui si occupa di definire 60 | // la struttura di presentazione di tutto il widget 61 | @override 62 | Widget build(BuildContext context) { 63 | return Row( 64 | mainAxisAlignment: MainAxisAlignment.center, 65 | children: [ 66 | CounterIncrementor(onPressed: _increment), 67 | const SizedBox(width: 16), 68 | CounterDisplay(count: _counter), 69 | ], 70 | ); 71 | } 72 | } 73 | 74 | void main() { 75 | runApp( 76 | const MaterialApp( 77 | home: Scaffold( 78 | body: Center( 79 | child: Counter(), 80 | ), 81 | ), 82 | ), 83 | ); 84 | } 85 | -------------------------------------------------------------------------------- /flutter/snippets/15-listview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | const title = 'Basic List'; 11 | 12 | return MaterialApp( 13 | title: title, 14 | home: Scaffold( 15 | appBar: AppBar( 16 | title: const Text(title), 17 | ), 18 | body: ListView( 19 | children: const [ 20 | ListTile( 21 | leading: Icon(Icons.map), 22 | title: Text('Map'), 23 | ), 24 | ListTile( 25 | leading: Icon(Icons.photo_album), 26 | title: Text('Album'), 27 | ), 28 | ListTile( 29 | leading: Icon(Icons.phone), 30 | title: Text('Phone'), 31 | ), 32 | ], 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flutter/snippets/16-listview-horizontal.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | const title = 'Horizontal List'; 11 | 12 | return MaterialApp( 13 | title: title, 14 | home: Scaffold( 15 | appBar: AppBar( 16 | title: const Text(title), 17 | ), 18 | body: Container( 19 | margin: const EdgeInsets.symmetric(vertical: 20), 20 | height: 200, 21 | child: ListView( 22 | scrollDirection: Axis.horizontal, 23 | children: [ 24 | Container( 25 | width: 160, 26 | color: Colors.red, 27 | ), 28 | Container( 29 | width: 160, 30 | color: Colors.blue, 31 | ), 32 | Container( 33 | width: 160, 34 | color: Colors.green, 35 | ), 36 | Container( 37 | width: 160, 38 | color: Colors.yellow, 39 | ), 40 | Container( 41 | width: 160, 42 | color: Colors.orange, 43 | ), 44 | ], 45 | ), 46 | ), 47 | ), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /flutter/snippets/17-gridview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | const title = 'Grid List'; 13 | 14 | return MaterialApp( 15 | title: title, 16 | home: Scaffold( 17 | appBar: AppBar( 18 | title: const Text(title), 19 | ), 20 | body: GridView.count( 21 | crossAxisCount: 2, 22 | children: List.generate(100, (index) { 23 | return Center( 24 | child: Text('Item $index'), 25 | ); 26 | }), 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /flutter/snippets/18-gridview-horizontal.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | const title = 'Grid List'; 13 | 14 | return MaterialApp( 15 | title: title, 16 | home: Scaffold( 17 | appBar: AppBar( 18 | title: const Text(title), 19 | ), 20 | body: GridView.count( 21 | crossAxisCount: 2, 22 | scrollDirection: Axis.horizontal, 23 | children: List.generate(100, (index) { 24 | return Center( 25 | child: Text('Item $index'), 26 | ); 27 | }), 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flutter/snippets/19-heterogeneous-list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp( 5 | MyApp( 6 | items: List.generate( 7 | 1000, 8 | (i) => i % 6 == 0 9 | ? DateItem('Data: $i') 10 | : MessageItem('User: $i', 'Testo del messaggio: $i'), 11 | ), 12 | ), 13 | ); 14 | } 15 | 16 | class MyApp extends StatelessWidget { 17 | final List items; 18 | 19 | const MyApp({super.key, required this.items}); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | const title = 'Lista Eterogenea'; 24 | 25 | return MaterialApp( 26 | title: title, 27 | home: Scaffold( 28 | appBar: AppBar( 29 | title: const Text(title), 30 | ), 31 | body: ListView.builder( 32 | // Let the ListView know how many items it needs to build. 33 | itemCount: items.length, 34 | // Provide a builder function. This is where the magic happens. 35 | // Convert each item into a widget based on the type of item it is. 36 | itemBuilder: (context, index) { 37 | final item = items[index]; 38 | 39 | return ListTile( 40 | title: item.buildTopPart(context), 41 | subtitle: item.buildBottomPart(context), 42 | ); 43 | }, 44 | ), 45 | ), 46 | ); 47 | } 48 | } 49 | 50 | abstract class ListItem { 51 | Widget buildTopPart(BuildContext context); 52 | Widget buildBottomPart(BuildContext context); 53 | } 54 | 55 | class DateItem implements ListItem { 56 | final String date; 57 | 58 | DateItem(this.date); 59 | 60 | @override 61 | Widget buildTopPart(BuildContext context) { 62 | return Text( 63 | date, 64 | style: Theme.of(context).textTheme.headlineSmall, 65 | ); 66 | } 67 | 68 | @override 69 | Widget buildBottomPart(BuildContext context) => const SizedBox.shrink(); 70 | } 71 | 72 | class MessageItem implements ListItem { 73 | final String user; 74 | final String body; 75 | 76 | MessageItem(this.user, this.body); 77 | 78 | @override 79 | Widget buildTopPart(BuildContext context) => Text(user); 80 | 81 | @override 82 | Widget buildBottomPart(BuildContext context) => Text(body); 83 | } 84 | -------------------------------------------------------------------------------- /flutter/snippets/2-con-materialapp-e-scaffold.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | title: 'La mia app', 14 | // Scaffold permette di assorbire il Material Design 15 | // e applicarlo automaticamente ai widget nella pagina 16 | home: const Scaffold(body: const Center(child: Text("Hello"))), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flutter/snippets/20-add-to-list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Aggiungi alla lista', 12 | home: MyHomePage(), 13 | ); 14 | } 15 | } 16 | 17 | class MyHomePage extends StatefulWidget { 18 | @override 19 | _MyHomePageState createState() => _MyHomePageState(); 20 | } 21 | 22 | class _MyHomePageState extends State { 23 | final List _items = ['Item 1']; 24 | 25 | void _addItem() { 26 | setState(() { 27 | int nextNum = _items.length + 1; 28 | _items.add('Item $nextNum'); 29 | }); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Scaffold( 35 | appBar: AppBar( 36 | title: Text('La mia lista'), 37 | ), 38 | body: ListView.builder( 39 | itemCount: _items.length, 40 | itemBuilder: (context, index) { 41 | return ListTile( 42 | title: Text(_items[index]), 43 | ); 44 | }, 45 | ), 46 | floatingActionButton: FloatingActionButton( 47 | onPressed: _addItem, 48 | tooltip: 'Aggiungi', 49 | child: Icon(Icons.add), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /flutter/snippets/21-lista-stile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | void main() { 5 | runApp(MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return MaterialApp( 12 | title: 'Aggiungi alla lista', 13 | home: MyHomePage(), 14 | theme: ThemeData( 15 | useMaterial3: true, 16 | // Definisce la luminosità e i colori di default 17 | colorScheme: ColorScheme.fromSeed( 18 | seedColor: Colors.purple, 19 | // ··· 20 | brightness: Brightness.dark, 21 | ), 22 | 23 | // Definisce il TextTheme di default. 24 | // Si usa per specificare lo stile per headlines, 25 | // titoli, corpo del testo, etc 26 | textTheme: TextTheme( 27 | displayLarge: const TextStyle( 28 | fontSize: 72, 29 | fontWeight: FontWeight.bold, 30 | ), 31 | // ··· 32 | titleLarge: GoogleFonts.oswald( 33 | fontSize: 30, 34 | fontStyle: FontStyle.italic, 35 | ), 36 | bodyMedium: GoogleFonts.merriweather(), 37 | displaySmall: GoogleFonts.pacifico(), 38 | ), 39 | ), 40 | ); 41 | } 42 | } 43 | 44 | class MyHomePage extends StatefulWidget { 45 | @override 46 | _MyHomePageState createState() => _MyHomePageState(); 47 | } 48 | 49 | class _MyHomePageState extends State { 50 | final List _items = ['Item 1']; 51 | 52 | void _addItem() { 53 | setState(() { 54 | int nextNum = _items.length + 1; 55 | _items.add('Item $nextNum'); 56 | }); 57 | } 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | return Scaffold( 62 | appBar: AppBar( 63 | title: Text('La mia lista'), 64 | ), 65 | body: ListView.builder( 66 | itemCount: _items.length, 67 | itemBuilder: (context, index) { 68 | return ListTile( 69 | title: Text(_items[index]), 70 | ); 71 | }, 72 | ), 73 | floatingActionButton: FloatingActionButton( 74 | onPressed: _addItem, 75 | tooltip: 'Aggiungi', 76 | child: Icon(Icons.add), 77 | ), 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /flutter/snippets/22-container-tema.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Aggiungi alla lista', 12 | home: Scaffold( 13 | body: Container( 14 | padding: const EdgeInsets.symmetric( 15 | horizontal: 12, 16 | vertical: 12, 17 | ), 18 | color: Theme.of(context).colorScheme.primary, 19 | child: Text( 20 | 'Testo con colore di sfondo', 21 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( 22 | color: Theme.of(context).colorScheme.onPrimary, 23 | ), 24 | ), 25 | ), 26 | )); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /flutter/snippets/23-theme-child.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Aggiungi alla lista', 12 | home: Scaffold( 13 | body: Container( 14 | padding: const EdgeInsets.symmetric( 15 | horizontal: 12, 16 | vertical: 12, 17 | ), 18 | color: Theme.of(context).colorScheme.primary, 19 | child: Text( 20 | 'Testo con colore di sfondo', 21 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( 22 | color: Theme.of(context).colorScheme.onPrimary, 23 | ), 24 | ), 25 | ), 26 | floatingActionButton: Theme( 27 | data: ThemeData( 28 | colorScheme: ColorScheme.fromSeed( 29 | seedColor: Colors.orange, 30 | ), 31 | ), 32 | child: FloatingActionButton( 33 | onPressed: () {}, 34 | child: const Icon(Icons.add), 35 | ), 36 | ))); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flutter/snippets/24-theme-override.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Aggiungi alla lista', 12 | home: Scaffold( 13 | body: Container( 14 | padding: const EdgeInsets.symmetric( 15 | horizontal: 12, 16 | vertical: 12, 17 | ), 18 | color: Theme.of(context).colorScheme.primary, 19 | child: Text( 20 | 'Testo con colore di sfondo', 21 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( 22 | color: Theme.of(context).colorScheme.onPrimary, 23 | ), 24 | ), 25 | ), 26 | floatingActionButton: Theme( 27 | data: Theme.of(context).copyWith( 28 | colorScheme: ColorScheme.fromSeed( 29 | seedColor: Colors.pink, 30 | ), 31 | ), 32 | child: FloatingActionButton( 33 | onPressed: () {}, 34 | child: const Icon(Icons.add), 35 | ), 36 | ))); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flutter/snippets/25-margin-padding.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Aggiungi alla lista', 12 | home: Scaffold( 13 | body: Container( 14 | margin: const EdgeInsets.all(8.0), 15 | padding: const EdgeInsets.symmetric( 16 | horizontal: 12, 17 | vertical: 24, 18 | ), 19 | color: Colors.red, 20 | child: Text( 21 | 'Questo testo è in grassetto', 22 | style: TextStyle( 23 | fontWeight: FontWeight.bold, backgroundColor: Colors.amber), 24 | ), 25 | ))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /flutter/snippets/26-textfield-textformfield.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | const appTitle = 'Form Styling Demo'; 11 | return MaterialApp( 12 | title: appTitle, 13 | home: Scaffold( 14 | appBar: AppBar( 15 | title: const Text(appTitle), 16 | ), 17 | body: const MyCustomForm(), 18 | ), 19 | ); 20 | } 21 | } 22 | 23 | class MyCustomForm extends StatelessWidget { 24 | const MyCustomForm({super.key}); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Column( 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | children: [ 31 | const Padding( 32 | padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16), 33 | child: TextField( 34 | decoration: InputDecoration( 35 | border: OutlineInputBorder(), 36 | hintText: 'Inserisci un termine per la ricerca...', 37 | ), 38 | ), 39 | ), 40 | Padding( 41 | padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), 42 | child: TextFormField( 43 | decoration: const InputDecoration( 44 | border: UnderlineInputBorder(), 45 | labelText: 'Inserisci il tuo nome utente', 46 | ), 47 | ), 48 | ), 49 | ], 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flutter/snippets/27-textfield-controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return const MaterialApp( 11 | title: 'Esempio valore TextField', 12 | home: MyCustomForm(), 13 | ); 14 | } 15 | } 16 | 17 | // Definiamo uno StatefulWidget 18 | class MyCustomForm extends StatefulWidget { 19 | const MyCustomForm({super.key}); 20 | 21 | @override 22 | State createState() => _MyCustomFormState(); 23 | } 24 | 25 | // Definiamo lo State corrispondente. 26 | // In questa classe tipicamente memorizziamo tutte le informazioni del form. 27 | class _MyCustomFormState extends State { 28 | // Creiamo un TextEditingController e lo usiamo per recuperare il valore nel TextField 29 | final myController = TextEditingController(); 30 | 31 | @override 32 | void dispose() { 33 | // dispose() serve a rimuovere il controller quando il widget non sarà più attivo 34 | myController.dispose(); 35 | super.dispose(); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: const Text('Esempio valore TextInput'), 43 | ), 44 | body: Padding( 45 | padding: const EdgeInsets.all(16), 46 | child: TextField( 47 | // Qui associamo effettivamente il controller al TextField 48 | controller: myController, 49 | ), 50 | ), 51 | floatingActionButton: FloatingActionButton( 52 | // Quando l'utente preme sul bottone, un alert mostra il contenuto del TextField 53 | onPressed: () { 54 | showDialog( 55 | context: context, 56 | builder: (context) { 57 | return AlertDialog( 58 | // myController.text è il testo nel TextField 59 | content: Text(myController.text), 60 | ); 61 | }, 62 | ); 63 | }, 64 | child: const Icon(Icons.text_fields), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /flutter/snippets/28-listen-to-change-textfield.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return const MaterialApp( 11 | title: 'Esempio Listener', 12 | home: MyCustomForm(), 13 | ); 14 | } 15 | } 16 | 17 | class MyCustomForm extends StatefulWidget { 18 | const MyCustomForm({super.key}); 19 | 20 | @override 21 | State createState() => _MyCustomFormState(); 22 | } 23 | 24 | class _MyCustomFormState extends State { 25 | final myController = TextEditingController(); 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | 31 | // Start listening to changes. 32 | myController.addListener(_printLatestValue); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | // In questo caso dispose() rimuove anche il listener che abbiamo aggiunto 38 | myController.dispose(); 39 | super.dispose(); 40 | } 41 | 42 | void _printLatestValue() { 43 | final text = myController.text; 44 | print('Secondo TextField: $text (${text.characters.length})'); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Scaffold( 50 | appBar: AppBar( 51 | title: const Text('Esempio Listener'), 52 | ), 53 | body: Padding( 54 | padding: const EdgeInsets.all(16), 55 | child: Column( 56 | children: [ 57 | TextField( 58 | onChanged: (text) { 59 | print('Primo TextField: $text (${text.characters.length})'); 60 | }, 61 | ), 62 | TextField( 63 | controller: myController, 64 | ), 65 | ], 66 | ), 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /flutter/snippets/29-form-validation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() => runApp(const MyApp()); 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | const appTitle = 'Validazione Form'; 11 | 12 | return MaterialApp( 13 | title: appTitle, 14 | home: Scaffold( 15 | appBar: AppBar( 16 | title: const Text(appTitle), 17 | ), 18 | body: const MyCustomForm(), 19 | ), 20 | ); 21 | } 22 | } 23 | 24 | // Rappresenta il nostro form 25 | class MyCustomForm extends StatefulWidget { 26 | const MyCustomForm({super.key}); 27 | 28 | @override 29 | MyCustomFormState createState() { 30 | return MyCustomFormState(); 31 | } 32 | } 33 | 34 | // Lo State memorizza le informazioni del form. 35 | class MyCustomFormState extends State { 36 | // Creiamo una chiave globale che identifica univocamente 37 | // il widget del Form e permette di fare la validazione. 38 | // NB: questa è una GlobalKey, FormState è una 39 | // classe che rappresenta lo State di un Form generico 40 | final _formKey = GlobalKey(); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | // La key è necessaria per creare il Form 45 | return Form( 46 | key: _formKey, 47 | child: Column( 48 | crossAxisAlignment: CrossAxisAlignment.start, 49 | children: [ 50 | TextFormField( 51 | // La proprietà validator accetta una funzione di callback 52 | // che riceve il testo inserito nel TextField e lo valida 53 | // In questo caso, diamo un errore se il testo è null o vuoto 54 | validator: (value) { 55 | if (value == null || value.isEmpty) { 56 | return 'Per favore, inserisci del testo.'; 57 | } 58 | return null; 59 | }, 60 | ), 61 | Padding( 62 | padding: const EdgeInsets.symmetric(vertical: 16), 63 | child: ElevatedButton( 64 | onPressed: () { 65 | // .validate() ritorna true se il form è valido, altrimenti false 66 | if (_formKey.currentState!.validate()) { 67 | // Se è valido, mostriamo una SnackBar 68 | // Tipicamente qui faremo una chiamata ad un server o 69 | // qualche task di update (es, scriviamo su un db) 70 | ScaffoldMessenger.of(context).showSnackBar( 71 | const SnackBar(content: Text('Sto processando i dati...')), 72 | ); 73 | } 74 | }, 75 | child: const Text('Invia'), 76 | ), 77 | ), 78 | ], 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /flutter/snippets/3-app-e-appbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MyAppBar extends StatelessWidget { 4 | const MyAppBar({required this.title, super.key}); 5 | 6 | // In una sottoclasse Widget i campi sono sempre final 7 | final Widget title; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | height: 56, // pixel logici 13 | padding: const EdgeInsets.symmetric(horizontal: 8), 14 | decoration: BoxDecoration(color: Colors.blue[500]), 15 | 16 | // Con Row renderizziamo i figli in orizzontale, da sx verso dx 17 | child: Row( 18 | children: [ 19 | // IconButton è un Button che oltre al testo accetta anche una icona 20 | const IconButton( 21 | icon: Icon(Icons.menu), 22 | tooltip: 'Navigation menu', 23 | onPressed: null, // Disabilitiamo il button 24 | ), 25 | 26 | // Expanded fa sì che il figlio occupi tutto lo spazio disponibile 27 | Expanded( 28 | child: title, 29 | ), 30 | 31 | const IconButton( 32 | icon: Icon(Icons.search), 33 | tooltip: 'Search', 34 | onPressed: null, 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | } 41 | 42 | class MyScaffold extends StatelessWidget { 43 | const MyScaffold({super.key}); 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | // Possiamo pensare a Material come una vista virtuale 48 | // in cui i nostri widget verranno renderizzati 49 | return Material( 50 | // Con Column renderizziamo i figli in verticale, dall'alto verso il basso 51 | child: Column( 52 | // Column ha due figli, MyAppBar e un Expanded 53 | children: [ 54 | // Il widget che rappresenta la barra in alto 55 | MyAppBar( 56 | title: Text( 57 | 'Example title', 58 | style: Theme.of(context) // lo stile del testo nella barra 59 | .primaryTextTheme 60 | .titleLarge, 61 | ), 62 | ), 63 | 64 | // Expanded qui ha un figlio Center che a sua volta contiene un Text 65 | const Expanded( 66 | child: Center( 67 | child: Text('Hello, world!'), 68 | ), 69 | ), 70 | ], 71 | ), 72 | ); 73 | } 74 | } 75 | 76 | void main() { 77 | runApp( 78 | const MaterialApp( 79 | // questo titolo apparirà nello switcher della piattaforma target 80 | // es, quando accediamo a tutte le app attive in Android 81 | title: 'My app', 82 | 83 | // Equivalente a React Native, permette di evitare che la UI del 84 | // sistema possa sovrapporsi ai widget dell'app (es, evitiamo il notch) 85 | home: SafeArea( 86 | child: MyScaffold(), 87 | ), 88 | ), 89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /flutter/snippets/30-load-json.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | home: Scaffold( 14 | appBar: AppBar( 15 | title: const Text('Load JSON from Assets'), 16 | ), 17 | body: const JsonLoader(), 18 | ), 19 | ); 20 | } 21 | } 22 | 23 | class JsonLoader extends StatefulWidget { 24 | const JsonLoader({super.key}); 25 | 26 | @override 27 | _JsonLoaderState createState() => _JsonLoaderState(); 28 | } 29 | 30 | class _JsonLoaderState extends State { 31 | late Future _jsonData; 32 | 33 | @override 34 | void initState() { 35 | super.initState(); 36 | _jsonData = loadJsonData(); 37 | } 38 | 39 | Future loadJsonData() async { 40 | String jsonString = await rootBundle.loadString('assets/data.json'); 41 | // Qui interpretiamo il JSON 42 | return json.decode(jsonString); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | // FutureBuilder si usa quando abbiamo un valore Future 48 | // che vogliamo usare per costruire il widget 49 | return FutureBuilder( 50 | future: _jsonData, 51 | builder: (context, snapshot) { 52 | if (snapshot.connectionState == ConnectionState.done) { 53 | if (snapshot.hasError) { 54 | return Text('Errore: ${snapshot.error}'); 55 | } 56 | 57 | // In questo caso, il nostro JSON è un array 58 | // di elementi con due campi, name e description 59 | return ListView.builder( 60 | itemCount: (snapshot.data as List).length, 61 | itemBuilder: (context, index) { 62 | return ListTile( 63 | title: Text(snapshot.data[index]['name']), 64 | subtitle: Text(snapshot.data[index]['description']), 65 | ); 66 | }, 67 | ); 68 | } 69 | 70 | // Show a loading spinner while waiting for the data 71 | return const CircularProgressIndicator(); 72 | }, 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /flutter/snippets/31-navigation-back-and-forth.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MaterialApp( 5 | title: 'Navigation Basics', 6 | home: RouteA(), 7 | )); 8 | } 9 | 10 | class RouteA extends StatelessWidget { 11 | const RouteA({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: const Text('Route A'), 18 | ), 19 | body: Center( 20 | child: ElevatedButton( 21 | child: const Text('Vai alla Route B'), 22 | onPressed: () { 23 | Navigator.push( 24 | context, 25 | MaterialPageRoute(builder: (context) => const RouteB()), 26 | ); 27 | }, 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | 34 | class RouteB extends StatelessWidget { 35 | const RouteB({super.key}); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Scaffold( 40 | appBar: AppBar( 41 | title: const Text('Route B'), 42 | ), 43 | body: Center( 44 | child: ElevatedButton( 45 | onPressed: () { 46 | Navigator.pop(context); 47 | }, 48 | child: const Text('Torna indietro!'), 49 | ), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /flutter/snippets/32-tabs.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const TabBarDemo()); 5 | } 6 | 7 | class TabBarDemo extends StatelessWidget { 8 | const TabBarDemo({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | home: DefaultTabController( 14 | length: 3, 15 | child: Scaffold( 16 | appBar: AppBar( 17 | bottom: const TabBar( 18 | tabs: [ 19 | Tab(icon: Icon(Icons.directions_car)), 20 | Tab(icon: Icon(Icons.directions_transit)), 21 | Tab(icon: Icon(Icons.directions_bike)), 22 | ], 23 | ), 24 | title: const Text('Tabs Demo'), 25 | ), 26 | body: const TabBarView( 27 | children: [ 28 | Icon(Icons.directions_car), 29 | Icon(Icons.directions_transit), 30 | Icon(Icons.directions_bike), 31 | ], 32 | ), 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flutter/snippets/33-todo-descr.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Todo { 4 | final String title; 5 | final String description; 6 | 7 | const Todo(this.title, this.description); 8 | } 9 | 10 | void main() { 11 | runApp( 12 | MaterialApp( 13 | title: 'Passing Data', 14 | home: TodosScreen( 15 | todos: List.generate( 16 | 20, 17 | (i) => Todo( 18 | 'Todo $i', 19 | 'A description of what needs to be done for Todo $i', 20 | ), 21 | ), 22 | ), 23 | ), 24 | ); 25 | } 26 | 27 | class TodosScreen extends StatelessWidget { 28 | const TodosScreen({super.key, required this.todos}); 29 | 30 | final List todos; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Scaffold( 35 | appBar: AppBar( 36 | title: const Text('Todos'), 37 | ), 38 | body: ListView.builder( 39 | itemCount: todos.length, 40 | itemBuilder: (context, index) { 41 | return ListTile( 42 | title: Text(todos[index].title), 43 | // Quando un utente tocca la ListTile, si naviga verso 44 | // il DetailScreen; nota bene: qui istanziamo un DetailScreen 45 | // e al contempo passiamo il todo corrente ad esso 46 | onTap: () { 47 | Navigator.push( 48 | context, 49 | MaterialPageRoute( 50 | builder: (context) => DetailScreen(todo: todos[index]), 51 | ), 52 | ); 53 | }, 54 | ); 55 | }, 56 | ), 57 | ); 58 | } 59 | } 60 | 61 | class DetailScreen extends StatelessWidget { 62 | // Il todo è necessario 63 | const DetailScreen({super.key, required this.todo}); 64 | 65 | // Memorizziamo qui il todo 66 | final Todo todo; 67 | 68 | @override 69 | Widget build(BuildContext context) { 70 | // Visualizziamo le informazioni del todo 71 | return Scaffold( 72 | appBar: AppBar( 73 | title: Text(todo.title), 74 | ), 75 | body: Padding( 76 | padding: const EdgeInsets.all(16), 77 | child: Text(todo.description), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /flutter/snippets/34-return-data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp( 5 | const MaterialApp( 6 | title: 'Returning Data', 7 | home: HomeScreen(), 8 | ), 9 | ); 10 | } 11 | 12 | class HomeScreen extends StatelessWidget { 13 | const HomeScreen({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: const Text('Returning Data Demo'), 20 | ), 21 | body: const Center( 22 | child: SelectionButton(), 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | class SelectionButton extends StatefulWidget { 29 | const SelectionButton({super.key}); 30 | 31 | @override 32 | State createState() => _SelectionButtonState(); 33 | } 34 | 35 | class _SelectionButtonState extends State { 36 | @override 37 | Widget build(BuildContext context) { 38 | return ElevatedButton( 39 | onPressed: () { 40 | _navigateAndDisplaySelection(context); 41 | }, 42 | child: const Text('Vai alla schermata di scelta'), 43 | ); 44 | } 45 | 46 | // Un metodo che lancia SelectionScreen e aspetta i 47 | // dati da Navigator.pop 48 | Future _navigateAndDisplaySelection(BuildContext context) async { 49 | // Navigator.push restituisce una Future che sarà completa 50 | // dopo l'invocazione di Navigator.pop nel SelectionScreen 51 | final result = await Navigator.push( 52 | context, 53 | MaterialPageRoute(builder: (context) => const SelectionScreen()), 54 | ); 55 | 56 | // Se un BuildContext è usato da uno StatefulWidgetù 57 | // dobbiamo controllare la mounted property dopo una operazione asincrona 58 | if (!context.mounted) return; 59 | 60 | // Dopo che il SelectionScreen restituisce un risultato, 61 | // nascondiamo le snackbar precedenti e mostriamo il nuovo 62 | ScaffoldMessenger.of(context) 63 | ..removeCurrentSnackBar() 64 | ..showSnackBar(SnackBar(content: Text('$result'))); 65 | } 66 | } 67 | 68 | class SelectionScreen extends StatelessWidget { 69 | const SelectionScreen({super.key}); 70 | 71 | @override 72 | Widget build(BuildContext context) { 73 | return Scaffold( 74 | appBar: AppBar( 75 | title: const Text('Scegli un\'opzione'), 76 | ), 77 | body: Center( 78 | child: Column( 79 | mainAxisAlignment: MainAxisAlignment.center, 80 | children: [ 81 | Padding( 82 | padding: const EdgeInsets.all(8), 83 | child: ElevatedButton( 84 | onPressed: () { 85 | // Chiude lo schermo e restituisce Yep! 86 | Navigator.pop(context, 'Yep!'); 87 | }, 88 | child: const Text('Yep!'), 89 | ), 90 | ), 91 | Padding( 92 | padding: const EdgeInsets.all(8), 93 | child: ElevatedButton( 94 | onPressed: () { 95 | // Chiude lo schermo e restituisce Nope. 96 | Navigator.pop(context, 'Nope.'); 97 | }, 98 | child: const Text('Nope.'), 99 | ), 100 | ) 101 | ], 102 | ), 103 | ), 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /flutter/snippets/4-creare-un-widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MyWidget extends StatelessWidget { 4 | const MyWidget({required this.text, required this.buttonText, super.key}); 5 | 6 | final String text; 7 | final String buttonText; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ 12 | Text(text), 13 | TextButton( 14 | child: Text(buttonText), 15 | onPressed: () { 16 | print("Cancellato"); 17 | }) 18 | ]); 19 | } 20 | } 21 | 22 | void main() { 23 | runApp( 24 | const MaterialApp( 25 | title: 'La mia app', 26 | home: SafeArea( 27 | child: Material( 28 | child: Column( 29 | mainAxisAlignment: MainAxisAlignment.center, 30 | crossAxisAlignment: CrossAxisAlignment.center, 31 | children: [ 32 | MyWidget(text: 'Il mio testo', buttonText: 'Cancella'), 33 | MyWidget(text: 'Un altro testo', buttonText: 'Non cancellare'), 34 | MyWidget(text: 'Testo a random', buttonText: 'Forse cancella'), 35 | ]), 36 | ), 37 | ), 38 | ), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /flutter/snippets/5-app-base-material-components.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Home extends StatelessWidget { 4 | const Home({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | // Si usa sempre Scaffold per definire il layout 9 | // nel caso in cui usiamo Material Components 10 | return Scaffold( 11 | // appBar accetta un oggetto AppBar che indica come è fatta 12 | // l'application bar (generalmente nella parte superiore dello schermo) 13 | appBar: AppBar( 14 | // leading è la parte sinistra dell'AppBar 15 | leading: const IconButton( 16 | // Icons mette a disposizione già una serie di icone generiche 17 | icon: Icon(Icons.menu), 18 | tooltip: 'Menu', 19 | onPressed: null, 20 | ), 21 | // title è il testo dell'AppBar 22 | title: const Text('Example title'), 23 | // actions accetta un array di widget (di solito IconButton) 24 | // indicanti le funzionalità mostrate nella parte destra dell'AppBar 25 | actions: const [ 26 | IconButton( 27 | icon: Icon(Icons.search), 28 | tooltip: 'Cerca', 29 | onPressed: null, 30 | ), 31 | ], 32 | ), 33 | 34 | // body è la parte centrale dello schermo 35 | body: const Center( 36 | child: Text('Hello, world!'), 37 | ), 38 | 39 | // floatingActionButton è tipico di Android e permette di specificare un 40 | // FloatingActionButton (qui il pulsantino in basso a destra con +) 41 | floatingActionButton: const FloatingActionButton( 42 | tooltip: 'Add', // used by assistive technologies 43 | onPressed: null, 44 | child: Icon(Icons.add), 45 | ), 46 | ); 47 | } 48 | } 49 | 50 | void main() { 51 | runApp( 52 | const MaterialApp( 53 | title: 'Material Components App', 54 | home: Home(), 55 | ), 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /flutter/snippets/6-column-row.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Home extends StatelessWidget { 4 | const Home({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Scaffold( 9 | body: const Center( 10 | child: const Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | const Text("Hello, prima riga"), 14 | const Text("Hello, seconda riga"), 15 | const Row( 16 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 17 | children: [ 18 | const Text("Terza riga, sinistra"), 19 | const Text("Terza riga, destra") 20 | ]) 21 | ]), 22 | ), 23 | ); 24 | } 25 | } 26 | 27 | void main() { 28 | runApp( 29 | const MaterialApp( 30 | title: 'Material Components App', 31 | home: Home(), 32 | ), 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /flutter/snippets/7-container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Home extends StatelessWidget { 4 | const Home({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Container( 10 | width: 136.0, 11 | height: 42.0, 12 | margin: const EdgeInsets.all(20.0), 13 | color: Colors.orange, 14 | child: Center(child: Text("Hello, World!")))); 15 | } 16 | } 17 | 18 | void main() { 19 | runApp( 20 | const MaterialApp( 21 | title: 'Material Components App', 22 | home: Scaffold(body: Home()), 23 | ), 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /flutter/snippets/8-stack.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Home extends StatelessWidget { 4 | const Home({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Stack(children: [ 10 | Container(width: 100, height: 100, color: Colors.yellow), 11 | Container(width: 50, height: 50, color: Colors.blue), 12 | Positioned(right: 0, bottom: 0, child: Text("Hello")) 13 | ])); 14 | } 15 | } 16 | 17 | void main() { 18 | runApp( 19 | const MaterialApp( 20 | title: 'Material Components App', 21 | home: Scaffold(body: Home()), 22 | ), 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /flutter/snippets/9-appbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | home: HomeScreen(), 12 | ); 13 | } 14 | } 15 | 16 | class HomeScreen extends StatelessWidget { 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text('Example AppBar'), 22 | backgroundColor: Colors.teal, 23 | actions: [ 24 | IconButton( 25 | icon: Icon(Icons.search), 26 | onPressed: () { 27 | print('Search button tapped!'); 28 | }, 29 | ), 30 | IconButton( 31 | icon: Icon(Icons.notifications), 32 | onPressed: () { 33 | print('Notifications button tapped!'); 34 | }, 35 | ), 36 | ], 37 | ), 38 | body: Center( 39 | child: Text('Hello, this is the home screen!'), 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | # Appunti JavaScript 2 | 3 | ## Equality e Inequality 4 | L'operatore `===` viene detto *strict equality operator* (anche *identity operator*) e controlla se i due operandi sono identici, tramite una definizione di egualianza stringente: 5 | 6 | 1. Se i due valori hanno tipi differenti, non sono uguali. 7 | 2. Se entrambi i valori sono null oppure entrambi sono undefined, sono uguali. 8 | 3. Se entrambi i valori sono true oppure entrambi sono false, sono uguali. 9 | 4. Se uno dei due valori è `NaN`, non sono uguali. 10 | 5. Se entrambi i valori sono numeri e hanno lo stesso valore, sono uguali (vale anche per 0 e -0). 11 | 6. Se entrambi i valori sono stringhe e contengono gli stessi valori nelle stesse posizioni, sono uguali. 12 | 7. Se entrambi i valori si riferiscono allo stesso oggetto, array o funzione, sono uguali. 13 | 14 | L'operatore `==` viene detto _equality operator_ e controlla se i due operandi sono uguali, tramite una definizione di egualianza più lasca: 15 | 16 | 1. Se entrambi gli operandi hanno lo stesso tipo, si applica la definuzione stringente di `===`. 17 | 2. Se gli operandi sono di tipo diverso, si controlla se: 18 | 1. Se un valore è `null` e l'altro `undefined`, sono uguali. 19 | 2. Se un valore è un numero e l'altro una stringa, si converte la stringa in numero e si riprova l'eguaglianza. 20 | 3. Se uno dei valori è `true`, si converte in 1 e si riprova l'eguaglianza. 21 | 4. Se uno dei valori è un oggetto e l'altro un numero o una stringa, si converte l'oggetto in tipo primitivo e si riprova l'eguaglianza. 22 | 5. Altre combinazioni, non sono uguali. 23 | 24 | ## Array 25 | 26 | ```javascript 27 | let undefs = [,,]; // Un array senza elementi ma con length 2 28 | 29 | let a = [1,2,3]; 30 | let b = [0, ...a, 4]; // ... viene chiamato spread operator e "spalma" gli elementi di a in b => [0,1,2,3,4] 31 | 32 | // best practice per creare una shallow copy di un array 33 | let original = [1,2,3]; 34 | let copy = [...original]; 35 | copy[0] = 1; // solo copy è modificato 36 | 37 | // rimuovere duplicati da un array 38 | let dups = [1,1,3,4,2,8,8,2]; 39 | let noDups = [..new Set(dups)]; // => [1,3,4,2,8] 40 | 41 | a = new Array(); // array vuoto, equivalente a [] 42 | a = new Array(10); // array di length 10 43 | a = new Array(2,3,4); // [2,3,4] 44 | Array.of() // => [] 45 | Array.of(1,2,3) // => [1,2,3] 46 | b = Array.from(a) // restituisce un nuovo array con gli elementi di a 47 | 48 | // l'operatore `in` controlla gli indici 49 | let x = [1,2,3]; 50 | 0 in x // => true 51 | 52 | // .push() aggiunge un elemento alla fine, modificando l'array 53 | let y = []; 54 | y.push("x"); // y = ["x"] 55 | 56 | // iterare su coppie (indice, valore) 57 | for (let [i, value] of x.entries()) { 58 | console.log(`Indice: ${i}, valore: ${value}`); 59 | } 60 | 61 | // forEach accetta una funzione il cui argomento sarà il valore corrente 62 | x.forEach(value => console.log(value)); 63 | 64 | 65 | // "to flat" un array significa eliminare la dimensione (ad esclusione della prima) più interna 66 | [1, [2,3]].flat() // => [1,2,3] 67 | 68 | // concatenare array 69 | let e = [1,2,3]; 70 | e.concat([4,5]) // => [1,2,3,4,5] 71 | 72 | // la combinazione di push() e pop() permette di 73 | // utilizzare gli array come delle pile 74 | let stack = []; 75 | stack.push(1,2); // stack == [1,2] 76 | stack.pop(); // stack = [1]; restituisce 2 77 | 78 | // una cosa può essere implementata utilizzando shift() 79 | let queue = []; 80 | queue.push(1,2); 81 | queu.shift(); // queue = [2]; restituisce 1 82 | 83 | // slice() restituisce una porzione contigua dell'array (anche detta, per l'appunto, slice) 84 | let f = [1,2,3,4,5]; 85 | f.slice(0,3) // => [1,2,3] 86 | 87 | // splice() rimuove un elemento da un array, inserisce nuove elementi o entrambe le cose 88 | let g = [1,2,3,4,5,6,7,8]; 89 | g.splice(4) // => [5,6,7,8]; g = [1,2,3,4] 90 | g.splice(1,2) // => [2,4]; g = [1,4] 91 | 92 | // fill() modifica ogni elemento di un array o di una slice con il valore dato 93 | let h = new Array(5); 94 | h.fill(2) // [2,2,2,2,2] 95 | 96 | // sort() ordina un array in modo LESSICOGRAFICO crescente; accetta anche una funzione di comparazione, la quale accetta due elementi e restituisce un valore < 0 se il primo è minore del secondo, > 0 se il primo è maggiore del secondo, altrimenti 0 97 | let a = [33, 4, 1111, 222]; 98 | a.sort() // => [1111, 222, 33, 4] 99 | a.sort((x,y) => x-y) // => [4, 33, 222, 1111] 100 | 101 | // dato un array di stringhe, a.join(c) crea una stringa in cui gli elementi di a sono riportati delimitati dal carattere c (di default una virgola) 102 | let a = [1, 2, 3]; 103 | a.join() // => "1,2,3" 104 | ``` 105 | 106 | ## Something something functional-ish 107 | ```javascript 108 | // Il metodo map() si invoca su di un iterable, accetta una funzione il cui parametro sarà il valore corrente dell'iterable, e restituisce un nuovo array 109 | let a = [1,2,3]; 110 | a.map(x => x*x) // => [1,4,9] 111 | 112 | // Il metodo filter() restituisce un sottoinsieme di elementi dell'iterable su cui è invocato. Accetta una funzione il cui parametro sarà il valore corrente dell'iterable, e la funzione deve essere un predicato (restituire true o false) 113 | let b = [2,5,4,7,8,6,2]; 114 | b.filter(x => x % 2 === 0) // => [2,4,8,6,2] 115 | 116 | // find() e findIndex() 117 | let c = [1,4,6,6,5]; 118 | c.find(x => x % 2 === 0) // => 4 119 | c.findIndex(x => x === 6) // => 2 120 | 121 | // every() e some() sono predicati che si applicano sugli array 122 | // every() è equivalente alla semantica del quantificatore for all/per ogni: restituisce true se il predicato è vero per tutti gli elementi dell'array; 123 | // some() è equivalente alla semantica del quantificatore esistenziale: restituisce true se il predicato è vero per almeno un elemento dell'array 124 | let d = [1,2,3,4,5]; 125 | a.every(x => x < 10) // => true 126 | a.some(x => x === 8) // => false 127 | 128 | // Processare gli array tramite funzioni 129 | let data = [1,1,3,5,5]; 130 | // calcolare media e stddev 131 | const sum = (x,y) => x+y; 132 | const square = x => x*x; 133 | 134 | // reduce() applica la funzione sum al primo argomento e al resto dell'array, poi al risultato ottenuto e alla parte restante, etc... 135 | let mean = data.reduce(sum) / data.length; // mean = 3 136 | let deviations = data.map(x => x - mean); 137 | let stddev = Math.sqrt(deviations.map(square).reduce(sum) / (data.length - 1)); 138 | ``` 139 | 140 | ## Funzioni 141 | 142 | - Vi è una importante differenza tra definire una funzione tramite una function declaration e una function expression, ovvero nel primo caso la funzione è creata prima che il codice contenuto in essa venga eseguito, mentre nel secondo caso la funzione esiste solo al momento della sua esecuzione 143 | 144 | ```javascript 145 | // function declaration 146 | function sum(a,b) { 147 | return a + x; 148 | } 149 | 150 | // function expression 151 | const squre = function(x) { return x * x; }; 152 | ``` 153 | 154 | - Le funzioni possono essere aggiunte tramite uno shorthand ad object literal 155 | 156 | ```javascript 157 | let calc = { 158 | operand1: 1, 159 | operand2: 1, 160 | add() { 161 | this.result = this.operand1 + this.operand2; 162 | } 163 | }; 164 | calc.add(); 165 | calc.result // => 2 166 | ``` 167 | 168 | - Se una funzione restituisce un oggetto, allora si può usare il valore restituito per invocare un suo metodo: questa pratica viene detta *method chaining* 169 | 170 | ```javascript 171 | let x = new Square().x(100).y(100).size(50).fill("blue"); 172 | ``` 173 | 174 | - Se una funzione viene invocata con un numero di parametri minore di quelli dichiarati, ai parametri restanti viene assegnato il loro valore di default (di solito `undefined`) 175 | 176 | ```javascript 177 | function getProps(o, a = []) { // a = [] indica il valore di default per a nel caso in cui getProps sia invocata senza la sua specifica 178 | for (let p in o) 179 | a.push(p); 180 | return a; 181 | } 182 | 183 | let o = {x: 1, y: 2}; 184 | let a = getProps(o); 185 | getProps(o, a) 186 | ``` 187 | 188 | - Possiamo scrivere funzioni che possano essere invocate con un numero arbitrario di parametri, utilizzando l'operatore spread 189 | 190 | ```javascript 191 | function sum(a,b,...rest) { 192 | let sum = a + b; 193 | for (let n of rest) 194 | sum += n; 195 | return sum; 196 | } 197 | 198 | sum(1,2) // => 3 199 | sum(1,2,3,4) // => 10 200 | ``` 201 | 202 | - Le funzioni in JS non sono valori primitivi ma speciali tipi di oggetti. Le proprietà di una funzione sono dei valori che appartengono alla funzione stessa, e sono condivisi tra le invocazioni: 203 | 204 | ```javascript 205 | myInt.counter = 0; 206 | function myInt() { 207 | return myInt.counter++; 208 | } 209 | myInt() // => 0 210 | myInt() // => 1 211 | 212 | // Compute factorials and cache results as properties of the function itself. 213 | function factorial(n) { 214 | if (Number.isInteger(n) && n > 0) { 215 | if (!(n in factorial)) { 216 | factorial[n] = n * factorial(n-1); 217 | } 218 | return factorial[n]; 219 | } else { 220 | return NaN; 221 | } 222 | } 223 | factorial[1] = 1; // Initialize the cache to hold this base case. 224 | factorial(6) // => 720 225 | factorial[5] // => 120; the call above caches this value 226 | ``` 227 | 228 | - Il punto precedente può essere rappresentato anche tramite una closure; una closure è la combinazione di una oggetto funzione e lo scope (l'insieme di binding di variabili) in cui le variabili della funzione sono valutate 229 | 230 | ```javascript 231 | let myInt = (function() { 232 | let counter = 0; 233 | return function() { return counter++; }; 234 | }) 235 | myInt() // => 0 236 | myInt() // => 1 237 | ``` 238 | 239 | ## Try/catch/finally 240 | 241 | ```javascript 242 | try { 243 | /* Questo codice potrebbe lanciare un'eccezione, sia direttamente 244 | tramite l'istruzione throw, sia indirettamente, invocando un 245 | metodo che lanci un'eccezione. */ 246 | } catch(e) { 247 | /* Le istruzioni in questo blocco sono eseguite sse il blocco 248 | try lancia un'eccezione; la variabile locale e si riferisce 249 | ad un oggetto di tipo Error o al valore che è stato lanciato 250 | dall'eccezione. */ 251 | } finally { 252 | /* Le istruzioni di questo blocco sono sempre eseguite, 253 | indipendentemente da cosa accade nel blocco try. */ 254 | } 255 | ``` 256 | 257 | ## import/export 258 | 259 | Le dichiarazioni `import` e `export` si usano per rendere disponibili valori definiti in un modulo di codice JS per un altro modulo. Un **modulo** è un file JS con un namespace proprio, indipendente da tutti gli altri moduli. L'unico modo affinché un valore definito in un modulo X possa essere usato in un modulo Y è se X esporta il valore con `export` e Y importa il valore con `import`. 260 | 261 | ```javascript 262 | /// file main.js 263 | import Circle from './geometry/circle.js'; 264 | 265 | /// file geometry/constants.js 266 | const PI = Math.PI; 267 | const TAU = 2 * PI; 268 | export { PI, TAU }; 269 | ``` 270 | 271 | ## Creazione di oggetti 272 | - Un oggetto creato `{}` viene detto _object literal_. 273 | - Un oggetto creato con `new f()` generalmente ha una classe associata. 274 | - Quasi tutti gli oggetti in JS hanno un secondo oggetto associato ad essi, e viene chiamato **prototipo**. Il primo oggetto eredita le proprietà dal prototipo. 275 | - Es, gli oggetti creati da `new Array()` usano `Array.prototype` come loro prototipo. 276 | - Con `Object.create(o)` si crea un oggetto avente `o` come prototipo. 277 | 278 | ## Varie 279 | - In modern JS (da ES6 in poi) si utilizza `let` per dichiarare le variabili. `var` porta con se diverse differenze, es ha function scope invece del block scope 280 | - Cosa significa? Che se ho diversi cicli `for` nello stesso blocco, posso usare `for (var i = ...)` tante volte senza problemi. 281 | - Destrutturazione 282 | ```javascript 283 | const f = (a,b) => { 284 | return [a+b, a-b]; 285 | } 286 | let [x,y] = f(0,1); 287 | let [x, ...y] = [1,2,3,4]; // y == [2,3,4] 288 | ``` 289 | - La comparazione tra due oggetti è fatta per riferimento, non per valore. 290 | ```javascript 291 | let y = [2,3,4]; 292 | y == [2,3,4] // => false 293 | ``` 294 | - L'operatore `+` funziona come segue: 295 | 1. Se uno dei due operandi è un oggetto, viene convertito in un tipo primitivo. Oggetti `Date` sono convertiti tramite il metodo `toString()`, mentre gli altri oggetti sono convertiti tramite `valueOf()`. In pratica, non tutti gli oggetti implementano un `valueOf()` quindi saranno comunque convertiti tramite `toString()`. 296 | 2. Dopo la conversione, se uno dei due operandi è una stringa, l'altro è convertito in stringa e si effettua la concatenazione. 297 | 3. Altrimenti, entrambi gli operandi sono convertiti in numeri (oppure `NaN`) e si effettua l'addizione. 298 | - È possibile usare il `do { ... } while(condition);`. 299 | - Il `for/of` utilizzato su di un oggetto itera sulle sue proprietà: 300 | ```javascript 301 | let o={x:1,y:2,z:3}; 302 | let keys = ""; 303 | for(let k of Object.keys(o)) { 304 | keys += k; 305 | } 306 | keys // => "xyz" 307 | ``` 308 | - Gli oggetti in JS sono array associativi (equivalenti ad hashmap o dizionari in altri linguaggi di programmazione) 309 | ```javascript 310 | let o = {a: 1, b: 2}; 311 | o.a // => 1 312 | o['a'] // => 1, nota bene: la proprietà è espressa come stringa 313 | ``` 314 | - Possiamo rimuovere una proprietà `x` di un oggetto `o` tramite `delete o.x;` 315 | - Per capire se un oggetto `o` abbia una certa proprietà `x`, possiamo usare `"x" in o`, il quale viene valutato `true` nel caso in cui la proprietà esista per l'oggetto (definita direttamente o eriditata). 316 | - `o.hasOwnProperty("x")` restituisce `true` se `x` è una proprietà definita direttamente (quindi non ereditata). 317 | - Enumerare le proprietà di un oggetto è cosa buona e giusta: 318 | ```javascript 319 | let o = {x: 1, y: 2, z: 42}; 320 | for (let p in o) { 321 | console.log(p); 322 | } 323 | ``` 324 | - Per ottenere la rappresentazione JSON di un oggetto si utilizza `JSON.stringify()`, il quale prende un oggetto e utilizza il metodo `toJSON` per la rappresentazione. Quest'ultimo deve essere implementato, se non già disponibile. -------------------------------------------------------------------------------- /js/char_freq_hist/hist.js: -------------------------------------------------------------------------------- 1 | // Eredita da Map (l'implementazione di hashmap di default in JavaScript) 2 | // get() fa sì che se la chiave non esiste, allora si restituisce un valore di default 3 | class DefaultMap extends Map { 4 | constructor(defaultValue) { 5 | super(); 6 | this.defaultValue = defaultValue; 7 | } 8 | 9 | get(key) { 10 | if (this.has(key)) 11 | return super.get(key); 12 | else 13 | return this.defaultValue; 14 | } 15 | } 16 | 17 | // La classe rappresentante il nostro istogramma 18 | class Histogram { 19 | constructor() { 20 | // mappa: carattere -> frequenza 21 | this.charToFreq = new DefaultMap(0); 22 | // il numero totale di caratteri letti 23 | this.n = 0; 24 | } 25 | 26 | // Parserizza una stringa e aggiunge i caratteri alla mappa 27 | add(text) { 28 | // s.replace(x,y) sostituisce la sottostringa x con y in s 29 | // in questo caso, x è una è l'espressione regolare /\s/g che si legge "trova tutti gli spazi": 30 | // /\s/ è un match, e indica "trova uno spazio bianco" 31 | // g indica che saranno considerati tutti i match 32 | text = text.replace(/\s/g, "").toUpperCase(); 33 | // iterare su una stringa significa accedere ad ogni carattere dal 0-esimo al n-1-esimo 34 | for (let char of text) { 35 | // la frequenza attualmente memorizzata per il carattere char 36 | let n = this.charToFreq.get(char); 37 | // h.set(k, v) modifica la chiave k nella mappa h con il valore v 38 | this.charToFreq.set(char, n+1); 39 | // aggiorniamo il numero totale di caratteri letti 40 | this.n++; 41 | } 42 | } 43 | 44 | // Overriding del metodo Object.toString() 45 | toString() { 46 | // L'operatore ... permette di creare un array da un oggetto iterable 47 | // (un oggetto è iterable se implementa il protocollo iterable tramite il metodo [Symbol.iterable]()) 48 | // In questo caso, la mappa viene "spacchettata" in un array contenente coppie (chiave, valore) 49 | let entries = [...this.charToFreq]; 50 | 51 | // a.sort() ordina in modo crescente oppure a.sort(f), dove f è una funzione che compara due elementi 52 | // f in questo caso viene anche detta "funzione anonima" (non ha un nome associato) 53 | // in questo caso, sia a che b sono due coppie (array di lunghezza 2) 54 | // e le ordiniamo rispetto al conteggio; se uguale, allora lessicograficamente 55 | entries.sort((a,b) => { 56 | if (a[1] === b[1]) 57 | return a[0] < b[0] ? -1 : 1; // if ternario: condizione ? vero : falso 58 | else 59 | return b[1] - a[1]; 60 | }) 61 | 62 | // convertiamo la frequenza in percentuale 63 | for (let entry of entries) { 64 | entry[1] = entry[1] / this.n * 100; 65 | } 66 | 67 | // a.filter(f) restituisce l'array contenente solo gli elementi di a che rispettono la condizione f 68 | // anche questo è un caso in cui utilizziamo una funzione anonima 69 | entries = entries.filter(entry => entry[1] >= 1); 70 | 71 | // a.map(f) invoca la funzione f per ogni elemento dell'array a e restituisce l'array con gli elementi modificati da f 72 | // anche qui funzione anonima che accetta un array di due elementi 73 | let bars = entries.map( 74 | // `${}` indica un template literal (NOTA BENE il simbolo `) 75 | // un template literale permette di "embeddare" una o più espressioni in una stringa 76 | // ${char} interpola nella stringa il valore di char 77 | // s.repeat(k) restituisce una stringa formata dalla concatenazione di s per k volte 78 | // Math.round(p) arrotonda p all'intero più vicino 79 | // p.toFixed(2) indica il numero di cifre decimali 80 | ([char,perc]) => `${char}: ${"#".repeat(Math.round(perc))} ${perc.toFixed(2)}` 81 | ); 82 | 83 | // a.join(s) concatena i valori in a utilizzando la stringa s come delimitatore 84 | return bars.join("\n"); 85 | } 86 | } 87 | 88 | // async indica una funzione asincrona, la quale restituisce un oggetto Promise 89 | // un Promise è un oggetto che rappresenta l'eventuale completamento (o fallimento) di una operazione asincrona e del suo risultato 90 | // la keyword async: 91 | // - permette di utilizzare "await" all'interno della funzione per mettere in pausa la sua esecuzione, 92 | // - l'esecuzione resta in pausa fino alla risoluzione del Promise 93 | // - non mette in pausa il thread principale 94 | async function hist() { 95 | // indica che l'encoding dei dati letti in stdin è utf-8 (interpreta i byte letti) 96 | process.stdin.setEncoding("utf-8"); 97 | let histogram = new Histogram(); 98 | 99 | /* 100 | the data comes in asynchronously as the user types input or as data is piped into the process. You can't predict when the next chunk of data will be available, and trying to read from the stream synchronously would either block the execution or not work as intended because the data might not be available immediately. 101 | */ 102 | 103 | // iteriamo in modo asincrono su stdin, ma perché? 104 | // i dati arrivono in modo asincrono (es, potrebbe inserirli l'utente manualmente oppure possono arrivare da una pipe), 105 | // quindi non possiamo predirre quando la prossima porzione di dati sarà disponibile; provare a leggere in modo sincrono 106 | // bloccherebbe l'esecuzione oppure avremmo un comportamento inatteso poiché i dati non sarebbero immediatamente disponibili. 107 | for await (let chunk of process.stdin) { 108 | histogram.add(chunk); 109 | } 110 | return histogram; 111 | } 112 | 113 | // invochiamo hist() inizialmente, la quale restituisce un Promise 114 | // f.then(g) permette di speficiare una funzione (detta funzione di callback) g 115 | // che verrà invocata quando f termina ed avviene la risoluzione del Promise 116 | hist().then(histogram => { 117 | console.log(histogram.toString()); 118 | }); -------------------------------------------------------------------------------- /js/hello.js: -------------------------------------------------------------------------------- 1 | // questo è un file contente codice JavaScript 2 | // l'interprete andrà ad effettuare una operazione di output 3 | // (scrivere sullo standard output) secondo ciò che dà a disposizione 4 | // il sistema operativo 5 | console.log("Ciao a tutti"); // System.out.println in Java 6 | console.log("Ciao ancora a tutti"); 7 | console.log("2 + 2 = " + (2+2)); -------------------------------------------------------------------------------- /js/javascript-recap-nosolutions.md: -------------------------------------------------------------------------------- 1 | # Esercizi su JavaScript 2 | 3 | ### Esercizio 1: Creazione e Modifica di un Oggetto 4 | Dichiarare un oggetto `student` con le proprietà `name`, `age` e `course`. Modifica poi il valore di `course` e aggiungi una nuova proprietà `grade`. 5 | 6 | ### Esercizio 2: Accesso agli Elementi di un Oggetto 7 | Dichiarare un oggetto `car` con le proprietà `brand`, `model` e `year`. Stampa il valore di `brand` e `year` utilizzando sia la notazione dot che la notazione bracket. 8 | 9 | ### Esercizio 3: Oggetto Vuoto e Aggiunta di Proprietà 10 | Dichiarare un oggetto vuoto `book` e aggiungi successivamente le proprietà `title`, `author` e `pages`. 11 | 12 | ### Esercizio 4: Verifica della Presenza di una Proprietà 13 | Dichiarare un oggetto `phone` con le proprietà `brand` e `model`. Verifica se la proprietà `price` esiste. 14 | 15 | --- 16 | 17 | ## Slide 11: JavaScript - Array 18 | 19 | ### Esercizio 1: Accesso agli Elementi 20 | Dichiarare un array `colors` contenente i valori "red", "green" e "blue". Stampa il primo e l’ultimo elemento. 21 | 22 | ### Esercizio 2: Aggiunta e Rimozione di Elementi 23 | Dichiarare un array `fruits` e aggiungi "apple" e "banana". Rimuovi il primo elemento. 24 | 25 | ### Esercizio 3: Iterazione su un Array 26 | Dichiarare un array `numbers` con i valori `[10, 20, 30, 40]` e stampa ciascun valore utilizzando un ciclo `for`. 27 | 28 | ### Esercizio 4: Contare gli Elementi di un Array 29 | Dichiarare un array `cities` e stampa il numero di elementi. 30 | 31 | --- 32 | 33 | ## Slide 15: JavaScript - Funzioni come Parametri 34 | 35 | ### Esercizio 1: Passare una Funzione come Argomento 36 | Scrivere una funzione `execute` che prende una funzione e un valore e restituisce il risultato della funzione applicata al valore. 37 | 38 | ### Esercizio 2: Funzione di Callback 39 | Scrivere una funzione repeatAction che accetta un'azione (funzione) e la esegue tre volte. 40 | 41 | --- 42 | 43 | ## Esercizio 1: Controllo del Flusso - Simulazione di una Coda 44 | Scrivere una funzione `processQueue` che simula una coda di utenti in attesa di essere serviti. La funzione accetta un array di nomi e li processa uno alla volta, stampando `Servendo [nome]...`. Se la coda è vuota, stampa `Nessun utente in attesa`. 45 | 46 | --- 47 | 48 | ## Esercizio 2: OOP - Classe Conto Bancario 49 | Creare una classe `BankAccount` che abbia i seguenti metodi: 50 | - `deposit(amount)`: aggiunge denaro al saldo. 51 | - `withdraw(amount)`: rimuove denaro se il saldo è sufficiente. 52 | - `getBalance()`: restituisce il saldo attuale. 53 | 54 | --- 55 | 56 | ## Esercizio 3: OOP - Ereditarietà 57 | Creare una classe `Person` con proprietà `name` e `age`, e un metodo `introduce()`. Poi creare una sottoclasse `Student` che eredita da `Person` e aggiunge una proprietà `course`. SovraScrivere il metodo `introduce()` per includere il corso di studio. 58 | 59 | --- 60 | 61 | ## Esercizio 4: Uso Avanzato di stdlib - Manipolazione Stringhe 62 | Scrivere una funzione `capitalizeWords` che prende una stringa e restituisce la stessa stringa con ogni parola che inizia con una lettera maiuscola. 63 | 64 | --- 65 | 66 | ## Esercizio 5: Uso Avanzato di stdlib - Generazione di Numeri Casuali 67 | Scrivere una funzione `randomNumbers` che genera un array di `n` numeri casuali compresi tra un minimo e un massimo. -------------------------------------------------------------------------------- /pwa/offline_serviceworker/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finalfire/mobprog-unisa/7a15135beed09cbefac3576587139911cbf5fd66/pwa/offline_serviceworker/.DS_Store -------------------------------------------------------------------------------- /pwa/offline_serviceworker/css/style.css: -------------------------------------------------------------------------------- 1 | h1 { color: red; } 2 | p { color: blue; } -------------------------------------------------------------------------------- /pwa/offline_serviceworker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Prova PWA 4 | 5 | 6 | 7 |

Questo è un titolo!

8 |

Quanto è bello questo corso!

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pwa/offline_serviceworker/js/app.js: -------------------------------------------------------------------------------- 1 | // se il mio browser SUPPORTA i ServiceWorker 2 | if ("serviceWorker" in navigator) { // l'oggetto navigator non è altro che il browser 3 | // navigator.serviceWorker sono le API 4 | // del browser per il supporto ai ServiceWorker 5 | // Registrare un ServiceWorker indica associare 6 | // il service worker alla mia web app 7 | navigator.serviceWorker.register("/serviceWorker.js") // crea un Promise 8 | .then(function(registration) { 9 | console.log("Service Worker registrato con scope:", registration.scope); 10 | }) 11 | .catch(function(error) { 12 | console.log("Registrazione Service Worker fallita:", error); 13 | }) 14 | } 15 | 16 | /* 17 | let bottone = document.getElementById("bottone"); 18 | bottone.addEventListener("click", (evento) => { 19 | console.log("Qualcuno mi ha cliccato"); 20 | })*/ -------------------------------------------------------------------------------- /pwa/offline_serviceworker/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // cattura tutti gli eventi di tipo "fetch" 2 | self.addEventListener("fetch", function(event) { 3 | console.log("Richiesta fetch per:", event.request.url); 4 | // event è un oggetto che ha dentro la Promise che racchiude 5 | // la fetch, e altre info 6 | event.respondWith( 7 | // mi chiedo se la fetch è fallita (per un qualsiasi errore) 8 | // se sì, catturo il tutto tramite il catch 9 | fetch(event.request).catch(function() { 10 | // il service worker fabbrica una nuova Response 11 | // con il testo "Sei offline" 12 | return new Response("Sei offline!") 13 | }) 14 | ); 15 | 16 | }); -------------------------------------------------------------------------------- /pwa/temperature_converter/converter.css: -------------------------------------------------------------------------------- 1 | html { 2 | background: rgb(243, 243, 243); 3 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 4 | font-size: 15pt; 5 | } 6 | 7 | html, body { 8 | height: 100%; 9 | margin: 0; 10 | } 11 | 12 | body { 13 | display: grid; 14 | place-items: center; 15 | } 16 | 17 | #converter { 18 | width: 15rem; 19 | padding: 2rem; 20 | border-radius: .5rem; 21 | box-shadow: 0 0 2rem 0 #0001; 22 | display: flex; 23 | flex-direction: column; 24 | align-items: center; 25 | } 26 | 27 | #converter input, #converter select { 28 | font-family: inherit; 29 | font-size: inherit; 30 | margin-block-end: 1rem; 31 | text-align: center; 32 | width: 10rem; 33 | } 34 | 35 | #converter #output-temp { 36 | font-size: 2rem; 37 | font-weight: bold; 38 | } -------------------------------------------------------------------------------- /pwa/temperature_converter/convertitore.js: -------------------------------------------------------------------------------- 1 | // Step 1: prendere tutti i valori dai componenti nel HTML 2 | // per riferirci ad un elemento HTML uso il suo id 3 | // e ottengo una variabile contenente un riferimento ad esso 4 | // tramite il metodo getElementById() dell'oggetto document 5 | // const indica che il riferimento contenuto non cambierà 6 | const inputField = document.getElementById("input-temp"); 7 | const fromUnitField = document.getElementById("input-unit"); 8 | const toUnitField = document.getElementById("output-unit"); 9 | const outputField = document.getElementById("output-temp"); 10 | const form = document.getElementById("converter"); 11 | 12 | // Step 2: implementare la logica della conversione 13 | // Step 2.1: implementare una funzione che prenda: 14 | // - value: il valore della temperatura 15 | // - l'unità da cui effettuare la conversione 16 | // - l'unità verso cui effettuare la conversione 17 | function convertTemp(value, fromUnit, toUnit) { 18 | // uso la stringa "c" per identificare il Celsius 19 | // uso la stringa "f" per identificare Farenheit 20 | // uso la stringa "k" per identificare Kelvin 21 | if (fromUnit === "c") { 22 | if (toUnit === "f") { 23 | return value * 9/5 + 32; 24 | } else if (toUnit === "k") { 25 | return value + 273.15; 26 | } 27 | return value; 28 | } 29 | if (fromUnit === "f") { 30 | if (toUnit === "c") { 31 | return (value - 32) * 5/9; 32 | } else if (toUnit === "k") { 33 | return (value + 459.67) * 5/9; 34 | } 35 | return value; 36 | } 37 | if (fromUnit === "k") { 38 | if (toUnit === "c") { 39 | return (value - 273.15); 40 | } else if (toUnit === "f") { 41 | return value * 9/5 - 459.67; 42 | } 43 | return value; 44 | } 45 | throw new Error("Invalid unit"); 46 | } 47 | 48 | form.addEventListener("input", () => { 49 | console.log("prova") 50 | // ottiene il valore da inputField; parseFloat fa parte della lib core di JavaScript 51 | // è necessario poiché inputField.value è una stringa 52 | const inputTemp = parseFloat(inputField.value); 53 | // ottiene il valore scelto nel primo select 54 | const fromUnit = fromUnitField.value; 55 | // ottiene il valore scelto nel secondo select 56 | const toUnit = toUnitField.value; 57 | // invoco la funzione per la conversione 58 | const outputTemp = convertTemp(inputTemp, fromUnit, toUnit); 59 | // scrivo il valore ottenuto nel outputField 60 | outputField.value = (Math.round(outputTemp * 100) / 100) + " " + toUnit.toUpperCase(); 61 | }); 62 | 63 | -------------------------------------------------------------------------------- /pwa/temperature_converter/icon512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finalfire/mobprog-unisa/7a15135beed09cbefac3576587139911cbf5fd66/pwa/temperature_converter/icon512.png -------------------------------------------------------------------------------- /pwa/temperature_converter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Conversione Temperatura 6 | 7 | 8 | 9 | 10 |

Converti la tua temperatura!

11 |
12 | 13 | 14 | 15 | 20 | 21 | 26 | 68 F 28 |
29 | 30 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /pwa/temperature_converter/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "en-us", 3 | "name": "Temperature converter app", 4 | "short_name": "Temperature converter", 5 | "description": "A basic temperature converter application that can convert to and from Celsius, Kelvin, and Fahrenheit", 6 | "start_url": "/", 7 | "background_color": "#2f3d58", 8 | "theme_color": "#2f3d58", 9 | "orientation": "any", 10 | "display": "standalone", 11 | "icons": [ 12 | { 13 | "src": "/icon512.png", 14 | "sizes": "512x512" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /pwa/temperature_converter/serviceworker.js: -------------------------------------------------------------------------------- 1 | // questo è il file contenente il codice del Service Worker 2 | const CACHE_NAME = 'temperature-converter-v1'; 3 | 4 | // STEP 1: aggiunge un eventListener per l'evento install 5 | // l'evento install è il primo evento del Service Worker 6 | // qui andiamo a scegliere quali file inserire nella cache 7 | self.addEventListener("install", event => { 8 | event.waitUntil( 9 | // waitUntil prende una closure (quindi una funzione anonima) 10 | (async () => { 11 | // caches è l'API JavaScript per accedere alla cache 12 | // caches.open(X) accede alla cache con nome X 13 | // se non esiste, la crea 14 | const cache = await caches.open(CACHE_NAME); 15 | // cache.addAll(A) aggiunge alla cache tutti gli elementi 16 | // nell'array A; aggiungere un elemento significa accedere 17 | // alla risorsa e immagazzinarla nella cache 18 | cache.addAll([ 19 | '/', 20 | '/convertitore.js', 21 | '/converter.css' 22 | ]); 23 | } 24 | )() // invoco la funzione data come parametro a waitUntil 25 | ); 26 | }); 27 | 28 | // STEP 2: per ogni evento fetch 29 | // accedo alla cache e mi chiedo se la risorsa richiesta 30 | // nell'evento fetch sia immagazzinata nella cache: se sì, la restituisco 31 | // se non è nella cache, allora provo a richiederla al server 32 | // e la aggiungo alla cache 33 | self.addEventListener("fetch", event => { 34 | event.respondWith((async () => { 35 | // accede alla cache 36 | const cache = await caches.open(CACHE_NAME); 37 | // controlla se la cache ha questa risorsa 38 | const cachedResponse = await cache.match(event.request); 39 | // se sì, la restituisco 40 | if (cachedResponse) { 41 | return cachedResponse; 42 | } else { 43 | try { 44 | // se arrivo qui, nella cache non ho la risorsa 45 | console.log(event); 46 | // quindi provo a richiederla tramite la connessione 47 | const fetchResponse = await fetch(event.request); 48 | // se va tutto bene, allora la inserisco nella cache 49 | cache.put(event.request, fetchResponse.clone()); 50 | // e poi vado a restituirla al browser 51 | return fetchResponse; 52 | } catch (e) { 53 | // entro dentro questo catch quando il fetch a riga 47 54 | // mi ha dato errore (esempio, non ho connessione internet) 55 | console.log("errore :("); 56 | } 57 | } 58 | })()); 59 | }); -------------------------------------------------------------------------------- /react-native/database_sqlite/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | SafeAreaView, 4 | StyleSheet, 5 | Button, 6 | View, 7 | Text, 8 | } from 'react-native'; 9 | import SQLite from 'react-native-sqlite-storage'; 10 | 11 | SQLite.enablePromise(true); 12 | const dbPromise = SQLite.openDatabase({name: 'mio_database.db', location: 'default'}); 13 | 14 | const App = () => { 15 | const [result, setResult] = React.useState(''); 16 | 17 | React.useEffect(() => { 18 | async function prepareDB() { 19 | const db = await dbPromise; 20 | await db.executeSql('CREATE TABLE IF NOT EXISTS utenti (matricola ... INTEGER PRIMARY KEY NOT NULL, nome TEXT, eta INTEGER, ruolo TEXT);'); 21 | } 22 | prepareDB(); 23 | }, []); 24 | 25 | const handleAddUser = async () => { 26 | try { 27 | const db = await dbPromise; 28 | const matricola = 0; 29 | await db.executeSql('INSERT INTO utenti (matricola, nome, eta, ruolo) VALUES (?, ?, ?, ?)', [matricola, 'Pluto', 25, 'Software Engineer']); 30 | setResult(`Aggiungo Pluto con matricola: ${matricola}`); 31 | } catch (error) { 32 | console.log(error); 33 | setResult('Errore nell\'aggiungere Pluto.'); 34 | } 35 | }; 36 | 37 | const readUser = async () => { 38 | try { 39 | const db = await dbPromise; 40 | var results = await db.executeSql('SELECT * FROM utenti WHERE matricola = 0'); 41 | console.log(results[0].rows.raw()); 42 | } catch (error) { 43 | console.log(error); 44 | } 45 | }; 46 | 47 | return ( 48 | 49 | 50 | 28 | Il tuo post: {route.params?.post} 29 | 30 | ) 31 | } 32 | 33 | const PostScreen = ({route, navigation}) => { 34 | const [post, setPost] = useState(''); 35 | return ( 36 | 37 | 43 | 53 | 54 | ) 55 | } 56 | 57 | const Stack = createNativeStackNavigator(); 58 | 59 | function App() { 60 | return ( 61 | 62 | 63 | 64 | 65 | 66 | 67 | ); 68 | } 69 | 70 | export default App; 71 | ``` 72 | 73 | Affinché tutto funzioni correttamente, questo codice necessita delle dipendenze `@react-navigation/native` e `@react-navigation/native-stack`. Per farlo, basta dichiararle nel `package.json`: 74 | 75 | ``` 76 | { 77 | "dependencies": { 78 | "@expo/vector-icons": "^14.0.0", 79 | "react-native-paper": "4.9.2", 80 | "react-native-screens": "~3.29.0", 81 | "@react-navigation/native": "^6.1.17", 82 | "@react-navigation/native-stack": "^6.9.26", 83 | "react-native-safe-area-context": "4.8.2" 84 | } 85 | } 86 | ``` 87 | 88 | Esse possono anche essere aggiunte automaticamente. Infatti, Expo Snack dovrebbe rivelare la presenza di dipendenze nel codice, e mostrare una opzione *[Add dependency]*, che inserisce automaticamente le dipendenze nel `package.json`. 89 | 90 | (Si ringrazia Luca Dello Russo per la segnalazione) -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-0.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function HomeScreen() { 7 | return ( 8 | 9 | Benvenuti! 10 | 11 | ); 12 | } 13 | 14 | const Stack = createNativeStackNavigator(); 15 | 16 | function App() { 17 | return ( 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-1.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen() { 7 | return ( 8 | 9 | Welcome! 10 | 11 | ); 12 | } 13 | 14 | function AboutScreen() { 15 | return ( 16 | 17 | Some info about the MobProg course... 18 | 19 | ); 20 | } 21 | 22 | const Stack = createNativeStackNavigator(); 23 | 24 | function App() { 25 | return ( 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-10.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {useState} from 'react'; 3 | import { View, Button, Text, TextInput } from 'react-native'; 4 | import { NavigationContainer } from '@react-navigation/native'; 5 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 6 | 7 | const MainScreen = ({route, navigation}) => { 8 | React.useEffect(() => { 9 | if (route.params?.post) { 10 | // fai qualcosa col post 11 | console.log("Post scritto: " + route.params.post); 12 | } 13 | }, [route.params?.post]); 14 | 15 | return ( 16 | 17 | 21 | Il tuo post: {route.params?.post} 22 | 23 | ) 24 | } 25 | 26 | const PostScreen = ({route, navigation}) => { 27 | const [post, setPost] = useState(''); 28 | return ( 29 | 30 | 36 | 46 | 47 | ) 48 | } 49 | 50 | const Stack = createNativeStackNavigator(); 51 | 52 | function App() { 53 | return ( 54 | 55 | 56 | 57 | 58 | 59 | 60 | ); 61 | } 62 | 63 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-11.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {useState} from 'react'; 3 | import { View, Button, Text, TextInput } from 'react-native'; 4 | import { NavigationContainer } from '@react-navigation/native'; 5 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 6 | import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; 7 | 8 | const Profile = () => { return Il mio profilo }; 9 | const Messages = () => { return I miei messaggi }; 10 | const Feed = () => { return Il mio feed }; 11 | const Settings = () => { return Le mie preferenze }; 12 | 13 | const Stack = createNativeStackNavigator(); 14 | const Tab = createBottomTabNavigator(); 15 | 16 | function Home() { 17 | return ( 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | 25 | function App() { 26 | return ( 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | ); 39 | } 40 | 41 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-2.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen() { 7 | return ( 8 | 9 | Welcome! 10 | 11 | ); 12 | } 13 | 14 | function AboutScreen() { 15 | return ( 16 | 17 | Some info about the MobProg course... 18 | 19 | ); 20 | } 21 | 22 | const Stack = createNativeStackNavigator(); 23 | 24 | function App() { 25 | return ( 26 | 27 | 28 | 30 | 31 | 32 | 33 | ); 34 | } 35 | 36 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-3.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { View, Button, Text } from "react-native"; 3 | import { NavigationContainer } from "@react-navigation/native"; 4 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; 5 | 6 | function WelcomeScreen({ navigation }) { 7 | return ( 8 | 9 | Welcome! 10 | 14 | 15 | ); 16 | } 17 | 18 | function AboutScreen() { 19 | return ( 20 | 21 | Some info about the MobProg course... 22 | 23 | ); 24 | } 25 | 26 | const Stack = createNativeStackNavigator(); 27 | 28 | function App() { 29 | return ( 30 | 31 | 32 | 37 | 38 | 39 | 40 | ); 41 | } 42 | 43 | export default App; 44 | -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-4.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Button, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen({navigation}) { 7 | return ( 8 | 9 | Welcome! 10 | 14 | 15 | ); 16 | } 17 | 18 | function AboutScreen({navigation}) { 19 | return ( 20 | 21 | Some info about the MobProg course... 22 | 26 | 27 | ); 28 | } 29 | 30 | const Stack = createNativeStackNavigator(); 31 | 32 | function App() { 33 | return ( 34 | 35 | 36 | 38 | 39 | 40 | 41 | ); 42 | } 43 | 44 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-5.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Button, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen({navigation}) { 7 | return ( 8 | 9 | Welcome! 10 | 14 | 15 | ); 16 | } 17 | 18 | function AboutScreen({navigation}) { 19 | return ( 20 | 21 | Some info about the MobProg course... 22 | 26 | 30 | 31 | ); 32 | } 33 | 34 | const Stack = createNativeStackNavigator(); 35 | 36 | function App() { 37 | return ( 38 | 39 | 40 | 42 | 43 | 44 | 45 | ); 46 | } 47 | 48 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-6.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Button, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen({navigation}) { 7 | return ( 8 | 9 | Welcome! 10 | 14 | 15 | ); 16 | } 17 | 18 | function AboutScreen({navigation}) { 19 | return ( 20 | 21 | Some info about the MobProg course... 22 | 26 | 30 | 34 | 35 | ); 36 | } 37 | 38 | const Stack = createNativeStackNavigator(); 39 | 40 | function App() { 41 | return ( 42 | 43 | 44 | 46 | 47 | 48 | 49 | ); 50 | } 51 | 52 | export default App; -------------------------------------------------------------------------------- /react-native/navigation/stack-navigation-7.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Button, Text } from 'react-native'; 3 | import { NavigationContainer } from '@react-navigation/native'; 4 | import { createNativeStackNavigator } from '@react-navigation/native-stack'; 5 | 6 | function WelcomeScreen({ navigation }) { 7 | return ( 8 | 9 | Welcome! 10 | 14 | Il tuo post: {route.params?.post} 15 | 16 | ) 17 | } 18 | 19 | const PostScreen = ({route, navigation}) => { 20 | const [post, setPost] = useState(''); 21 | return ( 22 | 23 | 29 | 39 | 40 | ) 41 | } 42 | 43 | const Stack = createNativeStackNavigator(); 44 | 45 | function App() { 46 | return ( 47 | 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | } 55 | 56 | export default App; -------------------------------------------------------------------------------- /react-native/snippets/basic-image-0.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | View, 4 | Image, 5 | Text 6 | } from "react-native"; 7 | 8 | const App = () => { 9 | return ( 10 | 11 | 17 | Ciao 18 | 19 | ) 20 | } 21 | 22 | export default App; -------------------------------------------------------------------------------- /react-native/snippets/basic-image-1.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | View, 4 | Image 5 | } from "react-native"; 6 | 7 | const BasicImage_1 = () => { 8 | return ( 9 | 10 | 13 | 14 | ) 15 | } 16 | 17 | export default BasicImage_1; -------------------------------------------------------------------------------- /react-native/snippets/basic-image-2.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | View, 4 | Image 5 | } from "react-native"; 6 | 7 | const BasicImage_2 = () => { 8 | return ( 9 | 10 | 15 | 16 | ) 17 | } 18 | 19 | export default BasicImage_2; -------------------------------------------------------------------------------- /react-native/snippets/basic-scrollview-0.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { ScrollView, Text } from "react-native"; 3 | 4 | const Comp = () => { 5 | return MobProg Unisa 2023/24 6 | } 7 | 8 | const App = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | export default App; -------------------------------------------------------------------------------- /react-native/snippets/basic-text-0.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Text, View } from 'react-native'; 3 | 4 | const BasicText_0 = () => { 5 | return ( 6 | 7 | Hello 8 | World! 9 | 10 | ? 11 | 12 | 13 | ); 14 | } 15 | 16 | export default BasicText_0; -------------------------------------------------------------------------------- /react-native/snippets/basic-textinput-0.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | View, 4 | TextInput 5 | } from "react-native"; 6 | 7 | const BasicTextInput_0 = () => { 8 | return ( 9 | 10 | 14 | 15 | ) 16 | } 17 | 18 | export default BasicTextInput_0; -------------------------------------------------------------------------------- /react-native/snippets/basic-textinput-1.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { View, Text, TextInput } from "react-native"; 3 | 4 | const App = () => { 5 | const [content, setContent] = useState(''); 6 | 7 | return ( 8 | 9 | 14 | Hai scritto: {content} 15 | 16 | ) 17 | } 18 | 19 | export default App; -------------------------------------------------------------------------------- /react-native/snippets/basic-view-0.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View } from 'react-native'; 3 | 4 | const BasicText_0 = () => { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | export default BasicText_0; -------------------------------------------------------------------------------- /react-native/snippets/extra-activityindicator-0.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ActivityIndicator, StyleSheet, View} from 'react-native'; 3 | 4 | const App = () => ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | const styles = StyleSheet.create({ 14 | container: { 15 | flex: 1, 16 | justifyContent: 'center', 17 | }, 18 | horizontal: { 19 | flexDirection: 'row', 20 | justifyContent: 'space-around', 21 | padding: 10, 22 | }, 23 | }); 24 | 25 | export default App; -------------------------------------------------------------------------------- /react-native/snippets/extra-alert-0.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet, Button, Alert} from 'react-native'; 3 | 4 | const App = () => { 5 | const creaAlert = () => 6 | Alert.alert('Alert', 'foo + bar = baz', [ 7 | {text: 'Va bene', onPress: () => console.log('Premuto!')}, 8 | ]); 9 | 10 | return ( 11 | 12 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ) 88 | } 89 | 90 | export default App; -------------------------------------------------------------------------------- /react-native/sorgenti_16032025/source_1.js: -------------------------------------------------------------------------------- 1 | import { Text } from 'react-native'; 2 | 3 | const sommaInStr = (a, b) => { 4 | let somma = a + b; 5 | let s = 'La somma tra ' + a + ' e ' + b + ' è pari a ' + somma; 6 | return somma; 7 | } 8 | 9 | const IlMioComponentePrincipale = () => { 10 | let r = sommaInStr(22, 20); 11 | return [{ r }, ciao]; 12 | } 13 | 14 | // export default serve a indicare a React Native qual è 15 | // l'entrypoint della mia app 16 | export default IlMioComponentePrincipale; -------------------------------------------------------------------------------- /react-native/sorgenti_16032025/source_2.js: -------------------------------------------------------------------------------- 1 | import {View, Text, TextInput} from 'react-native'; 2 | 3 | const Pippo = () => { 4 | let miostile = {color: 'blue',fontSize: 23}; 5 | return ( 6 | 7 | Ciao, io sono... 8 | 17 | 18 | ); 19 | } 20 | 21 | export default Pippo; -------------------------------------------------------------------------------- /react-native/sorgenti_16032025/source_3.js: -------------------------------------------------------------------------------- 1 | import {View, Text} from 'react-native'; 2 | 3 | type PlanetProps = { 4 | nome: string; 5 | colore: string; 6 | }; 7 | 8 | // props è un oggetto, i cui campi sono le 9 | // proprietà del componente Planet 10 | const Planet = (props: PlanetProps) => { 11 | // se il campo nome è undefined, quindi non è stato 12 | // passato un valore per la sua proprietà 13 | if (props.nome == undefined) { 14 | return Questo è il pianeta senza nome 15 | } 16 | return 17 | Questo è il pianeta { props.nome } con colore { props.colore} 18 | 19 | } 20 | 21 | const App = () => { 22 | return ( 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | } 30 | 31 | export default App; -------------------------------------------------------------------------------- /react-native/sorgenti_16032025/source_4.js: -------------------------------------------------------------------------------- 1 | import {View, Text, Button} from 'react-native'; 2 | 3 | const Counter = () => { 4 | let count = 0; 5 | return ( 6 | 7 | Il conteggio è: {count} 8 | 52 | 53 | ) 54 | } 55 | 56 | export default App; --------------------------------------------------------------------------------