Skip to content

Commit 8704927

Browse files
nojinjeongswift-kim
authored andcommitted
[wearable_rotary] Add wearable rotary plugin (#108)
* Add wearable rotary plugin * Implement example code * Fix some bugs * Update README * Update based on review * Update based on review * Update based on review * Update based on review * Update based on linter suggestions * Update based on review * Update based on review
1 parent 6bb8193 commit 8704927

22 files changed

+547
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ The _"non-endorsed"_ status means that the plugin is not endorsed by the origina
2828
| [**url_launcher_tizen**](packages/url_launcher) | [url_launcher](https://github.com/flutter/plugins/tree/master/packages/url_launcher) (1st-party) | [![pub package](https://img.shields.io/pub/v/url_launcher_tizen.svg)](https://pub.dev/packages/url_launcher_tizen) | No |
2929
| [**video_player_tizen**](packages/video_player) | [video_player](https://github.com/flutter/plugins/tree/master/packages/video_player) (1st-party) | [![pub package](https://img.shields.io/pub/v/video_player_tizen.svg)](https://pub.dev/packages/video_player_tizen) | No |
3030
| [**wakelock_tizen**](packages/wakelock) | [wakelock](https://github.com/creativecreatorormaybenot/wakelock) (3rd-party) | [![pub package](https://img.shields.io/pub/v/wakelock_tizen.svg)](https://pub.dev/packages/wakelock_tizen) | No |
31+
| [**wearable_rotary**](packages/wearable_rotary) | _N/A_ | [![pub package](https://img.shields.io/pub/v/wearable_rotary.svg)](https://pub.dev/packages/wearable_rotary) | _N/A_ |
3132
| [**webview_flutter_tizen**](packages/webview_flutter) | [webview_flutter](https://github.com/flutter/plugins/tree/master/packages/webview_flutter) (1st-party) | [![pub package](https://img.shields.io/pub/v/webview_flutter_tizen.svg)](https://pub.dev/packages/webview_flutter_tizen) | No |
3233
| [**wifi_info_flutter_tizen**](packages/wifi_info_flutter) | [wifi_info_flutter](https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter) (1st-party) | [![pub package](https://img.shields.io/pub/v/wifi_info_flutter_tizen.svg)](https://pub.dev/packages/wifi_info_flutter_tizen) | No |
3334

@@ -51,5 +52,6 @@ The _"non-endorsed"_ status means that the plugin is not endorsed by the origina
5152
| [**url_launcher_tizen**](packages/url_launcher) | ✔️ || ✔️ || No browser app |
5253
| [**video_player_tizen**](packages/video_player) | ✔️ | ✔️ | ✔️ || TV emulator issue |
5354
| [**wakelock_tizen**](packages/wakelock) | ✔️ | ✔️ ||| Cannot override system display setting|
55+
| [**wearable_rotary**](packages/wearable_rotary) | ✔️ | ✔️ ||| Not applicable for TV |
5456
| [**webview_flutter_tizen**](packages/webview_flutter) | ✔️ || ✔️ || Dependent library unavailable |
5557
| [**wifi_info_flutter_tizen**](packages/wifi_info_flutter) | ✔️ || ✔️ || API unsupported by emulators |

packages/wearable_rotary/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
.dart_tool/
3+
4+
.packages
5+
.pub/
6+
7+
build/

packages/wearable_rotary/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 1.0.0
2+
3+
* Initial release

packages/wearable_rotary/LICENSE

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the names of the copyright holders nor the names of the
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/wearable_rotary/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# wearable_rotary
2+
3+
Plugin that can listen to rotary events on Galaxy watch devices.
4+
5+
## Usage
6+
7+
To use this plugin, add wearable_rotary as a dependency in your pubspec.yaml file:
8+
9+
```yaml
10+
dependencies:
11+
wearable_rotary: ^1.0.0
12+
```
13+
14+
## Example
15+
16+
```dart
17+
// Import package.
18+
import 'package:wearable_rotary/wearable_rotary.dart';
19+
20+
// Be informed when the event (RotaryEvent.clockwise, RotaryEvent.counterClockwise) occurs.
21+
StreamSubscription<RotaryEvent> rotarySubscription =
22+
rotaryEvents.listen((RotaryEvent event) {
23+
if (event == RotaryEvent.clockwise) {
24+
// Do something.
25+
} else if (event == RotaryEvent.counterClockwise) {
26+
// Do something.
27+
}
28+
});
29+
30+
// Be sure to cancel on dispose.
31+
rotarySubscription.cancel();
32+
```
33+
34+
## Supported devices
35+
36+
This plugin is supported only on Galaxy watches.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
12+
# IntelliJ related
13+
*.iml
14+
*.ipr
15+
*.iws
16+
.idea/
17+
18+
# The .vscode folder contains launch configuration and tasks you configure in
19+
# VS Code which you may wish to be included in version control, so this line
20+
# is commented out by default.
21+
#.vscode/
22+
23+
# Flutter/Dart/Pub related
24+
**/doc/api/
25+
**/ios/Flutter/.last_build_id
26+
.dart_tool/
27+
.flutter-plugins
28+
.flutter-plugins-dependencies
29+
.packages
30+
.pub-cache/
31+
.pub/
32+
/build/
33+
34+
# Web related
35+
lib/generated_plugin_registrant.dart
36+
37+
# Symbolication related
38+
app.*.symbols
39+
40+
# Obfuscation related
41+
app.*.map.json
42+
43+
# Android Studio will place build artifacts here
44+
/android/app/debug
45+
/android/app/profile
46+
/android/app/release
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# wearable_rotary_example
2+
3+
Demonstrates how to use the wearable_rotary plugin.
4+
5+
## Getting Started
6+
7+
To run this app on your Tizen device, use [flutter-tizen](https://github.com/flutter-tizen/flutter-tizen).
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:wearable_rotary/wearable_rotary.dart';
5+
6+
class CustomPageView extends StatefulWidget {
7+
const CustomPageView(this.scrollDirection);
8+
9+
final Axis scrollDirection;
10+
11+
@override
12+
_CustomPageViewState createState() => _CustomPageViewState();
13+
}
14+
15+
class _CustomPageViewState extends State<CustomPageView> {
16+
StreamSubscription<RotaryEvent>? _rotarySubscription;
17+
final PageController _pager = PageController(initialPage: 0);
18+
int _currentPageIdx = 0;
19+
20+
@override
21+
void initState() {
22+
super.initState();
23+
_rotarySubscription = rotaryEvents.listen((RotaryEvent event) {
24+
if (event == RotaryEvent.clockwise) {
25+
if (_currentPageIdx != Colors.primaries.length - 1) {
26+
_pager.animateToPage(
27+
++_currentPageIdx,
28+
duration: const Duration(milliseconds: 500),
29+
curve: Curves.ease,
30+
);
31+
}
32+
} else if (event == RotaryEvent.counterClockwise) {
33+
if (_currentPageIdx != 0) {
34+
_pager.animateToPage(
35+
--_currentPageIdx,
36+
duration: const Duration(milliseconds: 500),
37+
curve: Curves.ease,
38+
);
39+
}
40+
}
41+
});
42+
}
43+
44+
@override
45+
void dispose() {
46+
super.dispose();
47+
_rotarySubscription?.cancel();
48+
_pager.dispose();
49+
}
50+
51+
@override
52+
Widget build(BuildContext context) {
53+
final String _title = widget.scrollDirection == Axis.vertical
54+
? 'verticalPageView'
55+
: 'HorizontalPageView';
56+
return Scaffold(
57+
appBar: AppBar(
58+
title: Text(_title),
59+
),
60+
body: PageView.builder(
61+
controller: _pager,
62+
scrollDirection: widget.scrollDirection,
63+
itemCount: Colors.primaries.length,
64+
itemBuilder: (BuildContext context, int index) {
65+
return Padding(
66+
padding: const EdgeInsets.all(8.0),
67+
child: Container(color: Colors.primaries[index]),
68+
);
69+
},
70+
onPageChanged: (int index) => _currentPageIdx = index,
71+
),
72+
);
73+
}
74+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import 'package:flutter/material.dart';
2+
3+
import './custom_page_view.dart';
4+
5+
void main() => runApp(
6+
MaterialApp(
7+
title: 'Rotary example app',
8+
home: MyApp(),
9+
),
10+
);
11+
12+
class MyApp extends StatelessWidget {
13+
final CustomPageView _horizontalPageView =
14+
const CustomPageView(Axis.horizontal);
15+
final CustomPageView _verticalPageView = const CustomPageView(Axis.vertical);
16+
@override
17+
Widget build(BuildContext context) {
18+
return Scaffold(
19+
appBar: AppBar(
20+
title: const Text('Rotary example app'),
21+
),
22+
body: Center(
23+
child: Column(
24+
mainAxisAlignment: MainAxisAlignment.center,
25+
children: <Widget>[
26+
ElevatedButton(
27+
child: const Text(
28+
'HorizontalPageView',
29+
style: TextStyle(fontSize: 15),
30+
),
31+
onPressed: () {
32+
Navigator.push<dynamic>(
33+
context,
34+
MaterialPageRoute<dynamic>(
35+
builder: (BuildContext context) => _horizontalPageView),
36+
);
37+
},
38+
),
39+
ElevatedButton(
40+
child: const Text(
41+
'VerticalPageView',
42+
style: TextStyle(fontSize: 15),
43+
),
44+
onPressed: () {
45+
Navigator.push<dynamic>(
46+
context,
47+
MaterialPageRoute<dynamic>(
48+
builder: (BuildContext context) => _verticalPageView),
49+
);
50+
},
51+
),
52+
],
53+
),
54+
),
55+
);
56+
}
57+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: wearable_rotary_example
2+
description: Demonstrates how to use the wearable_rotary plugin.
3+
4+
publish_to: "none"
5+
6+
environment:
7+
sdk: ">=2.12.0 <3.0.0"
8+
flutter: ">=2.0.0"
9+
10+
dependencies:
11+
flutter:
12+
sdk: flutter
13+
wearable_rotary:
14+
path: ../
15+
16+
flutter:
17+
uses-material-design: true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
flutter/
2+
.vs/
3+
*.user
4+
bin/
5+
obj/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Tizen.Flutter.Embedding;
2+
3+
namespace Runner
4+
{
5+
public class App : FlutterApplication
6+
{
7+
protected override void OnCreate()
8+
{
9+
base.OnCreate();
10+
11+
GeneratedPluginRegistrant.RegisterPlugins(this);
12+
}
13+
14+
static void Main(string[] args)
15+
{
16+
var app = new App();
17+
app.Run(args);
18+
}
19+
}
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Tizen.NET.Sdk/1.1.5">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>tizen40</TargetFramework>
6+
</PropertyGroup>
7+
8+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
9+
<DebugType>portable</DebugType>
10+
</PropertyGroup>
11+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
12+
<DebugType>none</DebugType>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="$(FlutterEmbeddingPath)" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<FlutterEphemeral Include="flutter\ephemeral\**\*" />
21+
<TizenTpkUserIncludeFiles Include="@(FlutterEphemeral)">
22+
<TizenTpkSubDir>%(RecursiveDir)</TizenTpkSubDir>
23+
</TizenTpkUserIncludeFiles>
24+
</ItemGroup>
25+
26+
</Project>
Loading
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="com.example.wearable_rotary_example" version="1.0.0" api-version="4.0" xmlns="http://tizen.org/ns/packages">
3+
<profile name="common"/>
4+
<ui-application appid="com.example.wearable_rotary_example" exec="Runner.dll" type="dotnet" multiple="false" taskmanage="true" nodisplay="false" api-version="4" launch_mode="single">
5+
<label>wearable_rotary_example</label>
6+
<icon>ic_launcher.png</icon>
7+
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true"/>
8+
<metadata key="http://tizen.org/metadata/direct-launch" value="yes"/>
9+
</ui-application>
10+
<feature name="http://tizen.org/feature/screen.size.all"/>
11+
</manifest>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import 'package:flutter/services.dart';
2+
3+
const String _channelName = 'flutter.wearable_rotary.channel';
4+
5+
const EventChannel _channel = EventChannel(_channelName);
6+
7+
Stream<RotaryEvent> get rotaryEvents {
8+
_rotaryEvents ??= _channel
9+
.receiveBroadcastStream()
10+
.map((dynamic event) => _parseEvent(event));
11+
return _rotaryEvents!;
12+
}
13+
14+
Stream<RotaryEvent>? _rotaryEvents;
15+
16+
enum RotaryEvent {
17+
clockwise,
18+
counterClockwise,
19+
}
20+
21+
RotaryEvent _parseEvent(dynamic event) {
22+
if (event is bool) {
23+
return event ? RotaryEvent.clockwise : RotaryEvent.counterClockwise;
24+
} else {
25+
throw PlatformException(
26+
code: 'type_cast',
27+
details: 'Platform plugin returns non-bool type for rotary event');
28+
}
29+
}

0 commit comments

Comments
 (0)