tizen_api 1.0.3 copy "tizen_api: ^1.0.3" to clipboard
tizen_api: ^1.0.3 copied to clipboard

Control your Samsung Tizen TV, writen in pure dart native. Trying the example project is highly encouraged :)

example/lib/main.dart

import 'dart:convert';
import 'dart:io';
import 'dart:math' hide log;

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tizen_api/tizen_api.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

late final SharedPreferences preferences;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  preferences = await SharedPreferences.getInstance();
  TizenHelperMethods.initialize();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.purple),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        primarySwatch: Colors.purple,
        dividerColor: Colors.purple,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  TV? _connectedTv;
  List<TV> tvs = [];
  Offset? _dragDelta;

  @override
  void initState() {
    super.initState();
    WakelockPlus.enable();
    scanNetwork();
  }

  Future<void> scanNetwork() async {
    await (NetworkInfo().getWifiIP()).then(
      (ip) async {
        final String subnet = ip!.substring(0, ip.lastIndexOf('.'));
        const port = 8002;
        for (var i = 0; i < 256; i++) {
          String ip = '$subnet.$i';
          await Socket.connect(ip, port,
                  timeout: const Duration(milliseconds: 50))
              .then((socket) async {
            await InternetAddress(socket.address.address)
                .reverse()
                .then((value) {
              addDeviceToList(socket.address.address);
            }).catchError((error) {
              addDeviceToList(socket.address.address);
            });
            socket.destroy();
          }).catchError((error) => null);
        }
      },
    );
    print('Done');
  }

  void addDeviceToList(String ip) async {
    final response = await Dio().get("http://$ip:8001/api/v2/");
    print("Found $ip");
    TV tv = TV.fromJson(response.data as Map<String, dynamic>);
    setState(() {
      tvs.add(tv);
    });
  }

  void setupStream() {
    if (TizenHelperMethods.selectedTv == null) return;
    TizenHelperMethods.selectedTv!
        .connectToSocket(preferences.getString("token"));

    TizenHelperMethods.selectedTv!.socketStream()?.listen((event) {
      print(event);
      if (TizenHelperMethods.selectedTv != _connectedTv) {
        setState(() {
          _connectedTv = TizenHelperMethods.selectedTv;
        });
      }
      try {
        final json = jsonDecode(event);
        final newToken = json["data"]["token"];

        if (newToken != null) {
          print("got new token $newToken");
          preferences.setString("token", newToken);
        }
      } catch (_) {}
    });
  }

  void _pressKey(KeyCodes key) {
    if (TizenHelperMethods.selectedTv == null) return;
    print("pressing $key");

    HapticFeedback.lightImpact();

    TizenHelperMethods.selectedTv!.addToSocket(key);
  }

  bool get connectedToTV =>
      _connectedTv != null && _connectedTv == TizenHelperMethods.selectedTv;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: DropdownButton<String>(
            hint: const Text("Select TV"),
            value: TizenHelperMethods.selectedTv?.name,
            onChanged: (String? tv) {
              setState(() {
                TizenHelperMethods.selectedTv =
                    tvs.firstWhere((element) => element.name == tv);
              });
              setupStream();
            },
            items: tvs.map<DropdownMenuItem<String>>((TV tv) {
              return DropdownMenuItem<String>(
                value: tv.name,
                child: Text(
                  tv.name,
                  style: const TextStyle(fontSize: 30),
                ),
              );
            }).toList(),
          ),
          actions: [
            IconButton(
              icon: const Icon(Icons.power_settings_new),
              onPressed: () {
                _pressKey(KeyCodes.KEY_POWER);
              },
            ),
          ],
        ),
        body: connectedToTV
            ? Column(
                children: [
                  Row(
                    children: [
                      Expanded(
                        child: DropdownButton<String>(
                          hint: const Text("Select Application"),
                          value: null,
                          onChanged: (String? application) {
                            if (TizenHelperMethods.selectedTv == null) return;
                            HapticFeedback.lightImpact();
                            TizenHelperMethods.selectedTv!
                                .forwardToApplication(application!);
                          },
                          items: TV.applications.keys
                              .map<DropdownMenuItem<String>>((String value) {
                            return DropdownMenuItem<String>(
                              value: value,
                              child: Text(
                                value,
                                style: const TextStyle(fontSize: 30),
                              ),
                            );
                          }).toList(),
                        ),
                      ),
                      Container(
                        padding: const EdgeInsets.symmetric(horizontal: 10),
                        child: InkWell(
                          child:
                              const Text("HDMI", textAlign: TextAlign.center),
                          onTap: () => _pressKey(KeyCodes.KEY_HDMI),
                        ),
                      ),
                    ],
                  ),
                  const Divider(),
                  Expanded(
                    child: Row(
                      children: [
                        Expanded(
                          child: GestureDetector(
                            onVerticalDragStart: (_) =>
                                _dragDelta = Offset.zero,
                            onVerticalDragUpdate: (d) {
                              _dragDelta = _dragDelta! + d.delta;

                              const threshold = 30.0;

                              if (_dragDelta!.distance > threshold) {
                                final dir =
                                    (_dragDelta!.direction / pi * 2 + 0.5)
                                        .floor();
                                switch (dir) {
                                  case -1:
                                    _pressKey(KeyCodes.KEY_VOLUP);
                                    _dragDelta =
                                        _dragDelta!.translate(0, threshold);
                                    break;
                                  case 1:
                                    _pressKey(KeyCodes.KEY_VOLDOWN);
                                    _dragDelta =
                                        _dragDelta!.translate(0, -threshold);
                                    break;
                                }
                              }
                            },
                            onVerticalDragEnd: (_) => _dragDelta = null,
                            onVerticalDragCancel: () => _dragDelta = null,
                            onTap: () => _pressKey(KeyCodes.KEY_MUTE),
                          ),
                        ),
                        const VerticalDivider(),
                        Expanded(
                          flex: 3,
                          child: GestureDetector(
                            onPanStart: (_) => _dragDelta = Offset.zero,
                            onPanUpdate: (d) {
                              _dragDelta = _dragDelta! + d.delta;
                              //TODO: Delay between key presses
                              const threshold = 60.0;

                              if (_dragDelta!.distance > threshold) {
                                final dir =
                                    (_dragDelta!.direction / pi * 2 + 0.5)
                                        .floor();
                                switch (dir) {
                                  case 2:
                                  case -2:
                                    _pressKey(KeyCodes.KEY_LEFT);
                                    _dragDelta = _dragDelta!
                                        .translate(threshold, -_dragDelta!.dy);
                                    break;
                                  case -1:
                                    _pressKey(KeyCodes.KEY_UP);
                                    _dragDelta = _dragDelta!
                                        .translate(-_dragDelta!.dx, threshold);
                                    break;
                                  case 0:
                                    _pressKey(KeyCodes.KEY_RIGHT);
                                    _dragDelta = _dragDelta!
                                        .translate(-threshold, -_dragDelta!.dy);
                                    break;
                                  case 1:
                                    _pressKey(KeyCodes.KEY_DOWN);
                                    _dragDelta = _dragDelta!
                                        .translate(-_dragDelta!.dx, -threshold);
                                    break;
                                }
                              }
                            },
                            onPanEnd: (_) => _dragDelta = null,
                            onPanCancel: () => _dragDelta = null,
                            onTap: () => _pressKey(KeyCodes.KEY_ENTER),
                          ),
                        ),
                      ],
                    ),
                  ),
                  const Divider(),
                  SizedBox(
                    height: 120,
                    child: Row(
                      children: [
                        Expanded(
                          child: InkWell(
                            child: const Center(child: Icon(Icons.arrow_back)),
                            onTap: () => _pressKey(KeyCodes.KEY_RETURN),
                          ),
                        ),
                        Expanded(
                          child: InkWell(
                            child:
                                const Center(child: Icon(Icons.home_outlined)),
                            onTap: () => _pressKey(KeyCodes.KEY_HOME),
                          ),
                        ),
                        Expanded(
                          child: InkWell(
                            child: const Center(child: Icon(Icons.pause)),
                            onTap: () => _pressKey(KeyCodes.KEY_ENTER),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(_connectedTv != TizenHelperMethods.selectedTv
                        ? "Waiting for TV to connect"
                        : "Select TV"),
                    const SizedBox(height: 20),
                    const CircularProgressIndicator(),
                  ],
                ),
              ));
  }
}
4
likes
0
points
50
downloads

Publisher

unverified uploader

Weekly Downloads

Control your Samsung Tizen TV, writen in pure dart native. Trying the example project is highly encouraged :)

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, network_info_plus, web_socket_channel

More

Packages that depend on tizen_api