├── .gitignore
├── LICENSE
├── README.md
├── TODO.txt
├── app
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── de
│ │ └── spiritcroc
│ │ └── modular_remote
│ │ ├── BReceiver.java
│ │ ├── BaseActivity.java
│ │ ├── CustomHorizontalScrollView.java
│ │ ├── CustomPreferenceFragment.java
│ │ ├── CustomScrollView.java
│ │ ├── CustomViewPager.java
│ │ ├── Display.java
│ │ ├── DragManager.java
│ │ ├── GlobalActionHandler.java
│ │ ├── GlobalActionSetting.java
│ │ ├── GlobalKeyService.java
│ │ ├── MainActivity.java
│ │ ├── Preferences.java
│ │ ├── ReceiverIpSelectorUser.java
│ │ ├── ResizeFrame.java
│ │ ├── SettingsActivity.java
│ │ ├── SettingsAdvancedFragment.java
│ │ ├── SettingsFragment.java
│ │ ├── SettingsGlobalActionsFragment.java
│ │ ├── SettingsMoreSpaceFragment.java
│ │ ├── ShortcutActivity.java
│ │ ├── TcpConnectionManager.java
│ │ ├── TcpInformation.java
│ │ ├── TimeSingleton.java
│ │ ├── TouchOverlay.java
│ │ ├── Util.java
│ │ ├── dialogs
│ │ ├── AboutDialog.java
│ │ ├── AddCommandLineFragmentDialog.java
│ │ ├── AddDisplayFragmentDialog.java
│ │ ├── AddFragmentDialog.java
│ │ ├── AddPageDialog.java
│ │ ├── AddSpinnerFragmentDialog.java
│ │ ├── AddToggleFragmentDialog.java
│ │ ├── AddWebViewFragmentDialog.java
│ │ ├── CommandInterface.java
│ │ ├── ConfigureToggleDialog.java
│ │ ├── CustomDialogFragment.java
│ │ ├── EditConnectionDialog.java
│ │ ├── EnterRawCommandDialog.java
│ │ ├── GlobalActionDialog.java
│ │ ├── GreetingDialog.java
│ │ ├── HideSubmenuItemsDialog.java
│ │ ├── OverlapWarningDialog.java
│ │ ├── OverwriteTypeDialog.java
│ │ ├── RemoveConnectionDialog.java
│ │ ├── RemoveContainerDialog.java
│ │ ├── SelectCommandDialog.java
│ │ ├── SelectConnectionDialog.java
│ │ ├── SelectContainerDialog.java
│ │ ├── SelectEditSubmenuDialog.java
│ │ ├── SelectFragmentsDialog.java
│ │ ├── SetupGridSizeDialog.java
│ │ ├── SortFragmentsDialog.java
│ │ └── SortPagesDialog.java
│ │ ├── dslv
│ │ ├── DragSortController.java
│ │ ├── DragSortCursorAdapter.java
│ │ ├── DragSortItemView.java
│ │ ├── DragSortItemViewCheckable.java
│ │ ├── DragSortListView.java
│ │ ├── ResourceDragSortCursorAdapter.java
│ │ ├── SimpleDragSortCursorAdapter.java
│ │ └── SimpleFloatViewManager.java
│ │ └── modules
│ │ ├── CommandLineFragment.java
│ │ ├── Container.java
│ │ ├── DisplayFragment.java
│ │ ├── HorizontalContainerFragment.java
│ │ ├── ModuleFragment.java
│ │ ├── PageContainerFragment.java
│ │ ├── ScrollContainerFragment.java
│ │ ├── SpinnerFragment.java
│ │ ├── ToggleFragment.java
│ │ ├── WebViewFragment.java
│ │ └── WidgetContainerFragment.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_action_container_drag_24dp.png
│ ├── ic_action_container_scroll_24dp.png
│ ├── ic_add_white_24dp.png
│ ├── ic_create_white_24dp.png
│ ├── ic_tune_white_24dp.png
│ ├── ic_widget_resize_handle.png
│ ├── widget_resize_frame.9.png
│ └── widget_resize_shadow.9.png
│ ├── drawable-mdpi
│ ├── ic_action_container_drag_24dp.png
│ ├── ic_action_container_scroll_24dp.png
│ ├── ic_add_white_24dp.png
│ ├── ic_create_white_24dp.png
│ ├── ic_tune_white_24dp.png
│ ├── ic_widget_resize_handle.png
│ ├── widget_resize_frame.9.png
│ └── widget_resize_shadow.9.png
│ ├── drawable-xhdpi
│ ├── ic_action_container_drag_24dp.png
│ ├── ic_action_container_scroll_24dp.png
│ ├── ic_add_white_24dp.png
│ ├── ic_create_white_24dp.png
│ ├── ic_tune_white_24dp.png
│ ├── ic_widget_resize_handle.png
│ ├── widget_resize_frame.9.png
│ └── widget_resize_shadow.9.png
│ ├── drawable-xxhdpi
│ ├── ic_action_container_drag_24dp.png
│ ├── ic_action_container_scroll_24dp.png
│ ├── ic_add_white_24dp.png
│ ├── ic_create_white_24dp.png
│ ├── ic_tune_white_24dp.png
│ ├── ic_widget_resize_handle.png
│ ├── widget_resize_frame.9.png
│ └── widget_resize_shadow.9.png
│ ├── drawable-xxxhdpi
│ ├── ic_action_container_drag_24dp.png
│ ├── ic_action_container_scroll_24dp.png
│ ├── ic_add_white_24dp.png
│ ├── ic_create_white_24dp.png
│ ├── ic_tune_white_24dp.png
│ ├── ic_widget_resize_handle.png
│ ├── widget_resize_frame.9.png
│ └── widget_resize_shadow.9.png
│ ├── drawable
│ └── ic_launcher_monochrome.xml
│ ├── layout
│ ├── abcd_alert_dialog_button_bar_material.xml
│ ├── abcd_alert_dialog_material.xml
│ ├── abcd_alert_dialog_title_material.xml
│ ├── activity_main.xml
│ ├── activity_shortcut.xml
│ ├── dialog_about.xml
│ ├── dialog_add_page.xml
│ ├── dialog_command_line_fragment.xml
│ ├── dialog_configure_toggle.xml
│ ├── dialog_display_fragment.xml
│ ├── dialog_edit_connection.xml
│ ├── dialog_enter_raw_command.xml
│ ├── dialog_global_action.xml
│ ├── dialog_select_fragment.xml
│ ├── dialog_setup_grid_size.xml
│ ├── dialog_sort.xml
│ ├── dialog_spinner_fragment.xml
│ ├── dialog_toggle_fragment.xml
│ ├── dialog_web_view_fragment.xml
│ ├── fragment_button.xml
│ ├── fragment_command_line.xml
│ ├── fragment_display.xml
│ ├── fragment_horizontal_container.xml
│ ├── fragment_page_container.xml
│ ├── fragment_scroll_container.xml
│ ├── fragment_spinner.xml
│ ├── fragment_toggle.xml
│ ├── fragment_web_view.xml
│ └── fragment_widget_container.xml
│ ├── menu
│ ├── menu_fragment_edit.xml
│ ├── menu_main.xml
│ └── menu_main_edit.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_foreground.png
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── dslv_attrs.xml
│ ├── strings.xml
│ ├── strings_activity_settings.xml
│ ├── strings_tcp_commands_general.xml
│ ├── strings_tcp_commands_pioneer.xml
│ └── styles.xml
│ └── xml
│ ├── preferences.xml
│ ├── preferences_advanced.xml
│ ├── preferences_global_actions.xml
│ └── preferences_more_space.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── guide_supporting_new_devices.md
├── icons
├── ic_action_container_drag_24dp.svg
├── ic_action_container_drag_36dp.svg
├── ic_action_container_scroll_24dp.svg
├── ic_action_container_scroll_36dp.svg
└── ic_launcher.svg
├── known_reference_sheets.md
├── settings.gradle
└── store
├── .featured-image.svg
├── description_full.txt
├── descritption_short.txt
├── featured-image.png
├── ic_launcher.png
└── screenshots
├── Screenshot_01.png
├── Screenshot_02.png
└── Screenshot_03.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *.apk
2 | *.iml
3 | output.json
4 | .gradle
5 | /local.properties
6 | /.idea
7 | /projectFilesBackup
8 | .DS_Store
9 | /build
10 | /captures
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Modular Remote
2 |
3 | The aim of this app is to provide the user a possibility to fully create their own remote out of several modules.
4 | Note it's no longer in active development, but I still use it to arrange a couple of webviews next to each other in pages, so I may push some updates every few years or so.
5 |
6 |
7 |
8 |
9 | Modular Remote is free, and open source.
10 | If you want to help by adding support for new remotely control-able devices, read [this guide](https://github.com/SpiritCroc/Modular-Remote/blob/master/guide_supporting_new_devices.md).
11 | Some very old to-do list can be found [here](https://github.com/SpiritCroc/Modular-Remote/blob/master/TODO.txt).
12 |
--------------------------------------------------------------------------------
/TODO.txt:
--------------------------------------------------------------------------------
1 | Stuff that could or should be done.
2 | The more x, the more important
3 |
4 | WIP:
5 | x - pioneer: complete strings_tcp_commands
6 |
7 | Fixes/Improvements:
8 | - if trying to add fragment to page that is null (can happen with wrong recreationKey), make error message (instead of crash?)
9 |
10 | Upgrades / New stuff:
11 |
12 | no coding required:
13 | - better featured image for play store (http://android-developers.blogspot.de/2011/10/android-market-featured-image.html)
14 | - more screenshots
15 | - feature video
16 |
17 | module upgrades:
18 | - button: type general: home, optionsMenu, open device volume dialog, display off, fullscreen on/off, navbar on/off, pagetabs on/off (last three also as response for toggle?)
19 | - button: possibility: image instead of written tag (built in, external source?)
20 | x - style: style editor → define global styles, each module references one style to apply
21 | select default style (used for new modules or when specified style not found)
22 | always at least one style (→ reset button?)
23 | style attributes:
24 | text color
25 | text size
26 | bg color
27 | …
28 | (also) apply for multiple modules in SelectModuleFragment?
29 | - Spinner: possibility to change order
30 | x - Page: Use toast as display: multi-selection-list to select displays (→toast can be used for several displays)
31 | Example usage: use as error display
32 | each display: possibility to chose between Toast.LENGTH_SHORT and Toast.LENGTH_LONG
33 |
34 | UI upgrades:
35 | - dialogFragments: add to back stack (particularly when selecting commands / adding fragments)
36 | @Override
37 | public void show(@NonNull FragmentManager manager, String tag) {
38 | super.show(manager, tag);
39 | getFragmentManager().beginTransaction().addToBackStack(null).commit();//Issue: dialogs are never shown again despite being in back stack
40 | }
41 | - immersive mode:
42 | when showing systemUI elements in immersive mode, hide elements again on click somewhere else
43 | when showing systemUI elements in immersive mode, do not allow clicks on other UI elements (prevent sending commands by accident)
44 | do not allow systemUI timeout < 2 or something
45 | if hidden menuBar appears, make it transparent (also other stuff transparent?)
46 | remove experimental: test on other devices
47 | fix: if actionBar hidden: issues when swiping down from statusBar (swiping up from navBar works)
48 | fix: possible not hiding actionBar after adding page
49 | fix: viewPager sometimes not updating on systemUI visibility changed
50 | - global padding settings, activity margin setting
51 | - CustomHorizontalScrollView + CustomScrollView: make snap depending on children measured size (inspiration by ChameleonOS app sidebar)
52 |
53 | other upgrades:
54 | - AddDisplayDialog: more characters in button_label_spinner_chars
55 | test on different APIs → don't show chars that are known to not show on certain APIs
56 | - first start:
57 | explanation how remote works
58 |
59 | New modules:
60 | - ExpandableContainer:
61 | option: onCreate:
62 | always expanded
63 | always collapsed
64 | remember from last session
65 | collapse if content has no connected connection + expand if reconnected
66 | - multi-function-button (as toggleButton, but with more (n) states (and no response))
67 | - Slider: e.g. for volume
68 |
69 | Functional upgrades:
70 | - option to keep screen on
71 | x - CommandEditor: Create chained commands (→ submenu "custom"), per RECEIVER_TYPE basis
72 | - Pref: remember last page
73 | - Settings: import/export fragments (portrait/landscape) → 4 preferences (allow fragment migration across different orientations)
74 |
75 |
76 | Stuff someone could add if they feel bored
77 | - WebViewFragment: optional actionBar with back, forward, reload-buttons (→if active, no optionsMenuEntry)
78 | - keyboard functionality
79 | - own toolbar instead of AppCompatActivity
80 | - infrared FB? → ConsumerIrManager; https://stackoverflow.com/questions/28794899/ir-emitter-and-android-5-0
81 | - Add Help-button to Add…Dialog → ExplainDialog to explain options
82 | - use different icon for launcher shortcuts than for launcher (take ic_launcher and change letters M and R to P and S or S and C or something)
83 | - own typeface based on Roboto (get from AOSP) with special chars (play, pause, etc. → ensure visibility on all devices)
84 | - tasker/locale plugin to send tcp commands
85 | - custom widgets
86 | - custom notifications
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def getGitDescription = { ->
4 | try {
5 | def out = new ByteArrayOutputStream()
6 | exec {
7 | commandLine 'git', 'describe', '--tags', '--dirty'
8 | standardOutput = out
9 | }
10 | return out.toString().trim()
11 | }
12 | catch (err) {
13 | return null
14 | }
15 | }
16 |
17 | android {
18 | compileSdkVersion 33
19 | buildToolsVersion '29.0.2'
20 | defaultConfig {
21 | applicationId 'de.spiritcroc.modular_remote'
22 | minSdkVersion 14
23 | targetSdkVersion 33
24 | versionCode 9
25 | versionName '0.7'
26 | buildConfigField "long", "TIMESTAMP", System.currentTimeMillis() + "L"
27 | buildConfigField "String", "GIT_DESCRIBE", "\"" + getGitDescription() + "\""
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | productFlavors {
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(dir: 'libs', include: ['*.jar'])
41 | implementation 'androidx.appcompat:appcompat:1.1.0'
42 | implementation 'androidx.preference:preference:1.1.0'
43 | implementation 'androidx.viewpager:viewpager:1.0.0'
44 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
45 | implementation 'androidx.legacy:legacy-support-v13:1.0.0'
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
35 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/BReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.net.ConnectivityManager;
25 |
26 | public class BReceiver extends BroadcastReceiver {
27 | @Override
28 | public void onReceive(Context context, Intent intent) {
29 | if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
30 | TcpConnectionManager.getInstance(context.getApplicationContext())
31 | .refreshConnections();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/BaseActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.ComponentName;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.ServiceConnection;
25 | import android.os.Bundle;
26 | import android.os.Handler;
27 | import android.os.IBinder;
28 | import android.os.Message;
29 | import android.os.Messenger;
30 | import android.os.RemoteException;
31 | import android.util.Log;
32 |
33 | import androidx.appcompat.app.AppCompatActivity;
34 |
35 | public abstract class BaseActivity extends AppCompatActivity {
36 |
37 | private static final String LOG_TAG = BaseActivity.class.getSimpleName();
38 |
39 | private static final boolean DEBUG = false;
40 |
41 | private Messenger mGlobalKeyService = null;
42 |
43 | private Messenger mGlobalKeyListener = new Messenger(new Handler() {
44 | @Override
45 | public void handleMessage(Message msg) {
46 | onGlobalKeyMessage(msg);
47 | }
48 | });
49 |
50 | private boolean mGlobalKeyServiceBound = false;
51 |
52 | protected ServiceConnection mGlobalKeyServiceConnection = new ServiceConnection() {
53 | @Override
54 | public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
55 | mGlobalKeyService = new Messenger(iBinder);
56 | mGlobalKeyServiceBound = true;
57 | }
58 |
59 | @Override
60 | public void onServiceDisconnected(ComponentName componentName) {
61 | mGlobalKeyService = null;
62 | mGlobalKeyServiceBound = false;
63 | }
64 | };
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 | startService(new Intent(this, GlobalKeyService.class));
70 | }
71 |
72 | @Override
73 | protected void onStart() {
74 | super.onStart();
75 | bindService(new Intent(this, GlobalKeyService.class), mGlobalKeyServiceConnection,
76 | Context.BIND_AUTO_CREATE);
77 | }
78 |
79 | @Override
80 | protected void onStop() {
81 | super.onStop();
82 | if (mGlobalKeyServiceBound) {
83 | unbindService(mGlobalKeyServiceConnection);
84 | mGlobalKeyServiceBound = false;
85 | }
86 | }
87 |
88 | @Override
89 | protected void onResume() {
90 | super.onResume();
91 | Message msg = Message.obtain(null, GlobalKeyService.ACTION_REGISTER_CLIENT);
92 | msg.replyTo = mGlobalKeyListener;
93 | sendGlobalKeyServiceMsg(msg);
94 | }
95 |
96 | @Override
97 | protected void onPause() {
98 | super.onPause();
99 | Message msg = Message.obtain(null, GlobalKeyService.ACTION_UNREGISTER_CLIENT);
100 | msg.replyTo = mGlobalKeyListener;
101 | sendGlobalKeyServiceMsg(msg);
102 | }
103 |
104 | public void sendGlobalKeyServiceMsg(Message message) {
105 | if (!mGlobalKeyServiceBound) {
106 | new RuntimeException("Discarding message, required service is not bound").printStackTrace();
107 | return;
108 | }
109 | try {
110 | mGlobalKeyService.send(message);
111 | } catch (RemoteException e) {
112 | e.printStackTrace();
113 | }
114 | }
115 |
116 | protected void onGlobalKeyMessage(Message message) {
117 | if (DEBUG) Log.v(LOG_TAG, "Received message " + message);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/CustomHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.Context;
22 |
23 | import androidx.annotation.NonNull;
24 | import androidx.core.view.MotionEventCompat;
25 | import android.util.AttributeSet;
26 | import android.view.MotionEvent;
27 | import android.view.View;
28 | import android.widget.HorizontalScrollView;
29 |
30 | import de.spiritcroc.modular_remote.modules.HorizontalContainerFragment;
31 |
32 | /**
33 | * Enables reasonable support for HorizontalContainerFragments within HorizontalContainerFragments
34 | */
35 |
36 | public class CustomHorizontalScrollView extends HorizontalScrollView {
37 | private float pointerX;
38 |
39 | private HorizontalContainerFragment wrapFragment;
40 |
41 | public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
42 | super (context, attrs);
43 | }
44 |
45 | @Override
46 | public boolean onInterceptTouchEvent(@NonNull MotionEvent ev) {
47 | final int action = MotionEventCompat.getActionMasked(ev);
48 |
49 | boolean result;
50 |
51 | switch (action) {
52 | case MotionEvent.ACTION_MOVE:
53 | if (!canScroll()) {
54 | // If it can't scroll, don't intercept touch events
55 | result = false;
56 | } else if ((ev.getX() > pointerX && !canScrollLeft()) ||
57 | (ev.getX() < pointerX && !canScrollRight())) {
58 | result = false;
59 | } else {
60 | if (wrapFragment != null && !wrapFragment.hasChildWithScrollX()) {
61 | // We're the smallest scroll view with this direction in this hierarchy,
62 | // so disallow the parents
63 | View view = this;
64 | while (view.getParent() != null && view.getParent() instanceof View) {
65 | if (view.getParent() instanceof CustomHorizontalScrollView) {
66 | // Only steal touch event from views with the same direction
67 | view.getParent().requestDisallowInterceptTouchEvent(true);
68 | }
69 | view = (View) view.getParent();
70 | }
71 | }
72 | result = super.onInterceptTouchEvent(ev);
73 | }
74 | break;
75 | default:
76 | result = super.onInterceptTouchEvent(ev);
77 | }
78 |
79 | pointerX = ev.getX();
80 |
81 | return result;
82 | }
83 |
84 | public void setWrapFragment(HorizontalContainerFragment wrapFragment) {
85 | this.wrapFragment = wrapFragment;
86 | }
87 |
88 | private boolean canScrollLeft() {
89 | return getScrollX() != 0;
90 | }
91 | private boolean canScrollRight() {
92 | return getMeasuredWidth() + getScrollX() != getChildAt(0).getMeasuredWidth();
93 | }
94 | public boolean canScroll() {
95 | return getMeasuredWidth() < getChildAt(0).getMeasuredWidth();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/CustomPreferenceFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.app.Activity;
22 | import android.content.SharedPreferences;
23 | import android.os.Message;
24 | import android.util.Log;
25 |
26 | import androidx.preference.Preference;
27 | import androidx.preference.PreferenceFragmentCompat;
28 |
29 | public abstract class CustomPreferenceFragment extends PreferenceFragmentCompat {
30 | private static final String LOG_TAG = CustomPreferenceFragment.class.getSimpleName();
31 |
32 | @Override
33 | public boolean onPreferenceTreeClick(Preference preference) {
34 | Activity activity = getActivity();
35 | if (activity instanceof SettingsActivity) {
36 | return ((SettingsActivity) activity).onPreferenceClick(preference) ||
37 | super.onPreferenceTreeClick(preference);
38 | } else {
39 | Log.w(LOG_TAG, "activity not instanceof SettingsActivity");
40 | return super.onPreferenceTreeClick(preference);
41 | }
42 | }
43 |
44 | protected void onGlobalKeyMessage(Message message) {}
45 |
46 | // Util methods
47 |
48 | protected int correctInteger(SharedPreferences sharedPreferences, String key, String value,
49 | int defaultValue){
50 | try {
51 | return Integer.parseInt(value);
52 | } catch (Exception e) {
53 | SharedPreferences.Editor editor = sharedPreferences.edit();
54 | editor.putString(key, String.valueOf(defaultValue));
55 | editor.apply();
56 | return defaultValue;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/CustomScrollView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.Context;
22 |
23 | import androidx.annotation.NonNull;
24 | import androidx.core.view.MotionEventCompat;
25 | import android.util.AttributeSet;
26 | import android.view.MotionEvent;
27 | import android.view.View;
28 | import android.widget.ScrollView;
29 |
30 | import de.spiritcroc.modular_remote.modules.ScrollContainerFragment;
31 |
32 | /**
33 | * Enables reasonable support for ScrollContainerFragments within ScrollContainerFragments
34 | */
35 |
36 | public class CustomScrollView extends ScrollView {
37 | private float pointerY;
38 |
39 | private ScrollContainerFragment wrapFragment;
40 |
41 | public CustomScrollView(Context context, AttributeSet attrs) {
42 | super (context, attrs);
43 | }
44 |
45 | @Override
46 | public boolean onInterceptTouchEvent(@NonNull MotionEvent ev) {
47 | final int action = MotionEventCompat.getActionMasked(ev);
48 |
49 | boolean result;
50 |
51 | switch (action) {
52 | case MotionEvent.ACTION_MOVE:
53 | if (!canScroll()) {
54 | // If it can't scroll, don't intercept touch events
55 | result = false;
56 | } else if ((ev.getY() > pointerY && !canScrollUp()) ||
57 | (ev.getY() < pointerY && !canScrollDown())) {
58 | result = false;
59 | } else {
60 | if (wrapFragment != null && !wrapFragment.hasChildWithScrollY()) {
61 | // We're the smallest scroll view with this direction in this hierarchy,
62 | // so disallow the parents
63 | View view = this;
64 | while (view.getParent() != null && view.getParent() instanceof View) {
65 | if (view.getParent() instanceof CustomScrollView) {
66 | // Only steal touch event from views with the same direction
67 | view.getParent().requestDisallowInterceptTouchEvent(true);
68 | }
69 | view = (View) view.getParent();
70 | }
71 | }
72 | result = super.onInterceptTouchEvent(ev);
73 | }
74 | break;
75 | default:
76 | result = super.onInterceptTouchEvent(ev);
77 | }
78 |
79 | pointerY = ev.getY();
80 |
81 | return result;
82 | }
83 |
84 | public void setWrapFragment(ScrollContainerFragment wrapFragment) {
85 | this.wrapFragment = wrapFragment;
86 | }
87 |
88 | private boolean canScrollUp() {
89 | return getScrollY() != 0;
90 | }
91 | private boolean canScrollDown() {
92 | return getMeasuredHeight() + getScrollY() != getChildAt(0).getMeasuredHeight();
93 | }
94 | public boolean canScroll() {
95 | return getMeasuredHeight() < getChildAt(0).getMeasuredHeight();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/CustomViewPager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.Context;
22 | import android.util.AttributeSet;
23 | import android.view.MotionEvent;
24 |
25 | import androidx.viewpager.widget.ViewPager;
26 |
27 | public class CustomViewPager extends ViewPager {
28 | private boolean scrollEnabled = true;
29 |
30 | public CustomViewPager(Context context) {
31 | super(context);
32 | }
33 |
34 | public CustomViewPager(Context context, AttributeSet attrs) {
35 | super(context, attrs);
36 | }
37 |
38 | @Override
39 | public boolean onTouchEvent(MotionEvent event) {
40 | return scrollEnabled && super.onTouchEvent(event);
41 | }
42 |
43 | @Override
44 | public boolean onInterceptTouchEvent(MotionEvent event) {
45 | return scrollEnabled && super.onInterceptTouchEvent(event);
46 | }
47 |
48 | public void setScrollEnabled(boolean scrollEnabled) {
49 | this.scrollEnabled = scrollEnabled;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/DragManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.util.Log;
22 |
23 | import de.spiritcroc.modular_remote.modules.Container;
24 | import de.spiritcroc.modular_remote.modules.ModuleFragment;
25 |
26 | public class DragManager {
27 | private static final String LOG_TAG = DragManager.class.getSimpleName();
28 | private static final boolean DEBUG = false;
29 |
30 | private static ModuleFragment dragFragment;
31 |
32 | private DragManager(){}
33 |
34 | public static boolean startDrag(ModuleFragment fragment) {
35 | // Make sure that parent containers don't replace dragged fragment
36 | if (dragFragment == null ||
37 | !(fragment instanceof Container)) {
38 | if (DEBUG) Log.v(LOG_TAG, "Start drag: " + fragment);
39 | dragFragment = fragment;
40 | fragment.onStartDrag();
41 | return true;
42 | } else {
43 | if (DEBUG) Log.d(LOG_TAG, "Don't start drag for " + fragment + ": already dragging " +
44 | dragFragment);
45 | return false;
46 | }
47 | }
48 | public static ModuleFragment stopDrag() {
49 | ModuleFragment fragment = dragFragment;
50 | if (DEBUG) Log.v(LOG_TAG, "Stop drag: " + fragment);
51 | dragFragment = null;
52 | if (fragment != null) {
53 | fragment.onStopDrag();
54 | }
55 | return fragment;
56 | }
57 |
58 | private static float dragStartX, dragStartY;
59 | public static void setLongPressPos(float dragStartX, float dragStartY) {
60 | DragManager.dragStartX = dragStartX;
61 | DragManager.dragStartY = dragStartY;
62 | }
63 | public static float getDragStartX() {
64 | return dragStartX;
65 | }
66 | public static float getDragStartY() {
67 | return dragStartY;
68 | }
69 | public static void cancelLongPress() {
70 | dragStartX = -1;
71 | }
72 | public static boolean isLongPressPossible() {
73 | return dragStartX != -1;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/GlobalActionHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.annotation.TargetApi;
22 | import android.content.SharedPreferences;
23 | import android.os.Message;
24 | import android.preference.PreferenceManager;
25 |
26 | @TargetApi(21)
27 | public abstract class GlobalActionHandler {
28 | private static final String LOG_TAG = GlobalActionHandler.class.getSimpleName();
29 |
30 | public static void enable(BaseActivity context) {
31 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
32 | Message volUpMsg = Message.obtain(null, GlobalKeyService.ACTION_ADD_ACTION, GlobalKeyService.EXTRA_ACTION_ID_VOLUME_UP, 0, sp.getString(Preferences.GLOBAL_ACTION_VOLUME_UP, ""));
33 | Message volDownMsg = Message.obtain(null, GlobalKeyService.ACTION_ADD_ACTION, GlobalKeyService.EXTRA_ACTION_ID_VOLUME_DOWN, 0, sp.getString(Preferences.GLOBAL_ACTION_VOLUME_DOWN, ""));
34 | context.sendGlobalKeyServiceMsg(volUpMsg);
35 | context.sendGlobalKeyServiceMsg(volDownMsg);
36 | }
37 |
38 | public static void disable(BaseActivity context) {
39 | Message msg = Message.obtain(null, GlobalKeyService.ACTION_REMOVE_ALL);
40 | context.sendGlobalKeyServiceMsg(msg);
41 | }
42 |
43 | /* todo (best to move all of this class to BaseActivity?)
44 | public static void updateSetting(Context context, GlobalActionSetting setting) {
45 | if (appContext == null) {
46 | Log.e(LOG_TAG, "updateSettings: missing context");
47 | return;
48 | }
49 | String key;
50 | if (setting == volumeUpSetting) {
51 | key = Preferences.GLOBAL_ACTION_VOLUME_UP;
52 | } else if (setting == volumeDownSetting) {
53 | key = Preferences.GLOBAL_ACTION_VOLUME_DOWN;
54 | } else {
55 | Log.w(LOG_TAG, "updateSetting: requested by unknown action " + setting);
56 | return;
57 | }
58 | PreferenceManager.getDefaultSharedPreferences(appContext).edit()
59 | .putString(key, setting.getRecreationKey()).apply();
60 | }
61 | */
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/GlobalActionSetting.java:
--------------------------------------------------------------------------------
1 | package de.spiritcroc.modular_remote;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.util.Log;
6 |
7 | // todo fix edit connection when disabled
8 | public class GlobalActionSetting implements TcpConnectionManager.TcpUpdateInterface {
9 |
10 | private static final String SEP = Util.RK_ATTRIBUTE_SEPARATOR;
11 | private static final String LOG_TAG = GlobalActionSetting.class.getSimpleName();
12 |
13 | private String ip;
14 | private TcpConnectionManager.ReceiverType type;
15 | private String clickCommand;
16 |
17 | private TcpConnectionManager.TcpConnection connection;
18 |
19 | public GlobalActionSetting(String ip, TcpConnectionManager.ReceiverType type,
20 | String clickCommand, TcpConnectionManager connectionManager) {
21 | this.ip = ip;
22 | this.type = type;
23 | this.clickCommand = clickCommand;
24 | if (connectionManager != null) {
25 | // Register for connection updates
26 | getConnection(connectionManager);
27 | }
28 | }
29 |
30 | public String getRecreationKey() {
31 | return Util.fixRecreationKey(ip + SEP + type.toString() + SEP + clickCommand + SEP, SEP);
32 | }
33 |
34 | public static GlobalActionSetting recoverFromRecreationKey(String key, TcpConnectionManager connectionManager) {
35 | if (!TextUtils.isEmpty(key)) {
36 | try {
37 | String[] args = Util.split(key, SEP, 0);
38 | String ip = args[0];
39 | TcpConnectionManager.ReceiverType type =
40 | TcpConnectionManager.ReceiverType.valueOf(args[1]);
41 | String clickCommand = args[2];
42 | return new GlobalActionSetting(ip, type, clickCommand, connectionManager);
43 | } catch (Exception e) {
44 | Log.w(LOG_TAG, "recoverFromRecreationKey: illegal key: " + key);
45 | }
46 | }
47 | // Return default
48 | return new GlobalActionSetting("", TcpConnectionManager.ReceiverType.UNSPECIFIED, "", connectionManager);
49 | }
50 |
51 | public String getIp() {
52 | return ip;
53 | }
54 |
55 | public TcpConnectionManager.ReceiverType getType() {
56 | return type;
57 | }
58 |
59 | public String getClickCommand() {
60 | return clickCommand;
61 | }
62 |
63 | public boolean isVoid() {
64 | return TextUtils.isEmpty(clickCommand) || TextUtils.isEmpty(ip);
65 | }
66 |
67 | public boolean isConnected() {
68 | return !isVoid() && connection != null && connection.isConnected();
69 | }
70 |
71 | public String getSummary(Context context) {
72 | return TcpConnectionManager.getInstance(context.getApplicationContext())
73 | .getCommandNameFromResource(context.getResources(), null, type, clickCommand, null);
74 | }
75 |
76 | public TcpConnectionManager.TcpConnection getConnection(TcpConnectionManager manager) {
77 | if (connection == null) {
78 | connection = manager.requireConnection(this);
79 | }
80 | return connection;
81 | }
82 |
83 | public void closeConnection() {
84 | if (connection != null) {
85 | connection.removeListener(this);
86 | connection = null;
87 | }
88 | }
89 |
90 | public boolean sendCommand(Context context) {
91 | if (isVoid()) {
92 | return false;
93 | } else {
94 | getConnection(TcpConnectionManager.getInstance(context))
95 | .sendRawCommand(clickCommand);
96 | return connection.isConnected();
97 | }
98 | }
99 |
100 | @Override
101 | public void update(TcpInformation information) {}
102 |
103 | @Override
104 | public void setConnectionValues(String ip, TcpConnectionManager.ReceiverType type) {
105 | this.ip = ip;
106 | this.type = type;
107 | // todo GlobalActionHandler.updateSetting(this);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/ReceiverIpSelectorUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | public interface ReceiverIpSelectorUser {
22 | void setReceiverType(TcpConnectionManager.ReceiverType receiverType);
23 | void resumeDismiss();//resume stuff that waits for OverwriteTypeDialog, don't forget to dismiss!
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.Intent;
22 | import android.os.Bundle;
23 | import android.os.Message;
24 | import android.view.MenuItem;
25 |
26 | import androidx.appcompat.app.ActionBar;
27 | import androidx.preference.Preference;
28 | import androidx.preference.PreferenceScreen;
29 |
30 | public class SettingsActivity extends BaseActivity {
31 |
32 | private CustomPreferenceFragment preferenceFragment;
33 |
34 | private static final String EXTRA_PREFERENCE_FRAGMENT =
35 | "de.spiritcroc.modular_remote.extra.preference_fragment";
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | String preferenceKey = getIntent().getStringExtra(EXTRA_PREFERENCE_FRAGMENT);
41 | preferenceFragment = getNewPreferenceFragment(preferenceKey);
42 | getSupportFragmentManager().beginTransaction().replace(android.R.id.content, preferenceFragment)
43 | .commit();
44 |
45 | ActionBar actionBar = getSupportActionBar();
46 | if (actionBar != null) {
47 | actionBar.setDisplayHomeAsUpEnabled(true);
48 | }
49 | }
50 |
51 | @Override
52 | protected void onResume() {
53 | super.onResume();
54 |
55 | ActionBar actionBar = getSupportActionBar();
56 | if (actionBar != null) {
57 | actionBar.setTitle(preferenceFragment.getPreferenceScreen().getTitle());
58 | }
59 | }
60 |
61 | @Override
62 | public boolean onOptionsItemSelected(MenuItem item) {
63 | switch (item.getItemId()) {
64 | case android.R.id.home:
65 | finish();
66 | return true;
67 | default:
68 | return super.onOptionsItemSelected(item);
69 | }
70 | }
71 |
72 | public boolean onPreferenceClick(Preference preference) {
73 | if (preference instanceof PreferenceScreen) {
74 | String fragmentClass = preference.getFragment();
75 | if (fragmentClass != null) {
76 | startActivity(new Intent(this, SettingsActivity.class)
77 | .putExtra(EXTRA_PREFERENCE_FRAGMENT, fragmentClass));
78 | return true;
79 | }
80 | }
81 | return false;
82 | }
83 |
84 | private CustomPreferenceFragment getNewPreferenceFragment(String preferenceFragment) {
85 | if (preferenceFragment != null) {
86 | try {
87 | return (CustomPreferenceFragment) Class.forName(preferenceFragment).newInstance();
88 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
89 | ClassCastException e) {
90 | e.printStackTrace();
91 | }
92 | }
93 | return new SettingsFragment();
94 | }
95 |
96 | @Override
97 | protected void onGlobalKeyMessage(Message message) {
98 | preferenceFragment.onGlobalKeyMessage(message);
99 | super.onGlobalKeyMessage(message);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/SettingsMoreSpaceFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.SharedPreferences;
22 | import android.os.Bundle;
23 |
24 | import androidx.preference.CheckBoxPreference;
25 | import androidx.preference.EditTextPreference;
26 |
27 | public class SettingsMoreSpaceFragment extends CustomPreferenceFragment
28 | implements SharedPreferences.OnSharedPreferenceChangeListener {
29 |
30 | private CheckBoxPreference fullscreenPreference;
31 | private CheckBoxPreference hideNavBarPreference;
32 | private EditTextPreference systemUiTimeoutPreference;
33 |
34 | @Override
35 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
36 | addPreferencesFromResource(R.xml.preferences_more_space);
37 |
38 | systemUiTimeoutPreference =
39 | (EditTextPreference) findPreference(Preferences.SYSTEM_UI_TIMEOUT);
40 | fullscreenPreference = (CheckBoxPreference) findPreference(Preferences.FULLSCREEN);
41 | hideNavBarPreference =
42 | (CheckBoxPreference) findPreference(Preferences.HIDE_NAVIGATION_BAR);
43 | }
44 |
45 | private void init() {
46 | setSystemUiTimeoutSummary();
47 | setSystemUiTimeoutEnabled();
48 | }
49 |
50 | @Override
51 | public void onResume() {
52 | super.onResume();
53 | getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
54 | init();
55 | }
56 |
57 | @Override
58 | public void onPause() {
59 | super.onPause();
60 | getPreferenceScreen().getSharedPreferences()
61 | .unregisterOnSharedPreferenceChangeListener(this);
62 | }
63 |
64 | @Override
65 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
66 | if (Preferences.SYSTEM_UI_TIMEOUT.equals(key)) {
67 | setSystemUiTimeoutSummary();
68 | } else if (Preferences.FULLSCREEN.equals(key)) {
69 | setSystemUiTimeoutEnabled();
70 | } else if (Preferences.HIDE_NAVIGATION_BAR.equals(key)) {
71 | setSystemUiTimeoutEnabled();
72 | }
73 | }
74 |
75 | private void setSystemUiTimeoutSummary() {
76 | int value = correctInteger(getPreferenceManager().getSharedPreferences(),
77 | Preferences.SYSTEM_UI_TIMEOUT, systemUiTimeoutPreference.getText(), 3);
78 | systemUiTimeoutPreference.setSummary(getResources()
79 | .getQuantityString(R.plurals.pref_system_ui_timeout, value, value));
80 | }
81 |
82 | private void setSystemUiTimeoutEnabled() {
83 | systemUiTimeoutPreference.setEnabled(fullscreenPreference.isChecked() ||
84 | hideNavBarPreference.isChecked());
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/TimeSingleton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.os.Handler;
22 | import android.util.Log;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Calendar;
26 |
27 | public class TimeSingleton {
28 | private static final String LOG_TAG = TimeSingleton.class.getSimpleName();
29 | private static final boolean DEBUG = false;
30 |
31 | private static TimeSingleton instance;
32 | private int updateInterval;
33 | private ArrayList timeListeners;
34 | private Handler timeHandler;
35 | private String time;
36 |
37 | private TimeSingleton(int updateInterval) {
38 | setUpdateInterval(updateInterval);
39 | timeHandler = new Handler();
40 | timeListeners = new ArrayList<>();
41 | }
42 |
43 | public static TimeSingleton getInstance(int updateInterval) {
44 | if (instance == null) {
45 | instance = new TimeSingleton(updateInterval);
46 | } else {
47 | instance.setUpdateInterval(updateInterval);
48 | }
49 | return instance;
50 | }
51 | public static TimeSingleton getInstance() {// Do not overwrite updateInterval
52 | if (instance == null) {
53 | instance = new TimeSingleton(500);// Default
54 | }
55 | return instance;
56 | }
57 | private void setUpdateInterval(int updateInterval) {
58 | this.updateInterval = updateInterval;
59 | }
60 |
61 | private void setTime(String time) {
62 | for (int i = 0; i < timeListeners.size(); i++) {
63 | timeListeners.get(i).setTime(time);
64 | }
65 | }
66 |
67 | public void registerListener(TimeListener listener) {
68 | if (!timeListeners.contains(listener)) {
69 | if (timeListeners.isEmpty()) {
70 | onResume();
71 | }
72 | timeListeners.add(listener);
73 | listener.setTime(time);
74 | }
75 | }
76 | public void unregisterListener(TimeListener listener) {
77 | listener.setTime("");
78 | timeListeners.remove(listener);
79 | if (timeListeners.isEmpty()) {
80 | onPause();
81 | }
82 | }
83 |
84 | private void onResume() {
85 | timeHandler.postDelayed(timeUpdateTask, updateInterval);
86 | }
87 | private void onPause() {
88 | timeHandler.removeCallbacks(timeUpdateTask);
89 | }
90 |
91 | private Runnable timeUpdateTask = new Runnable() {
92 | @Override
93 | public void run() {
94 | if (updateInterval > 0) {
95 | Calendar calendar = Calendar.getInstance();
96 | int hour = calendar.get(Calendar.HOUR_OF_DAY);
97 | int minute = calendar.get(Calendar.MINUTE);
98 | int second = calendar.get(Calendar.SECOND);
99 | time = hour + ":";
100 | if (minute < 10) {
101 | time += "0";
102 | }
103 | time += minute + ":";
104 | if (second < 10) {
105 | time += "0";
106 | }
107 | time += second + "";
108 | if (DEBUG) Log.v(LOG_TAG, "Update time for " + timeListeners.size() + " listeners");
109 | setTime(time);
110 | timeHandler.postDelayed(this, updateInterval);
111 | } else {
112 | setTime("");
113 | }
114 | }
115 | };
116 |
117 | public interface TimeListener {
118 | void setTime(String time);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/TouchOverlay.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote;
20 |
21 | import android.content.Context;
22 | import android.view.MotionEvent;
23 | import android.widget.FrameLayout;
24 |
25 | /**
26 | * An overlay to receive all touches and forward them to the resizeFrame
27 | */
28 | public class TouchOverlay extends FrameLayout {
29 | ResizeFrame resizeFrame;
30 |
31 | public TouchOverlay(Context context, ResizeFrame resizeFrame) {
32 | super(context);
33 | this.resizeFrame = resizeFrame;
34 | }
35 |
36 | @Override
37 | public boolean onTouchEvent(MotionEvent event) {
38 | return resizeFrame.handleTouchEvent(this, event);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/AboutDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.view.View;
26 | import android.widget.TextView;
27 |
28 | import androidx.appcompat.app.AlertDialog;
29 | import androidx.fragment.app.DialogFragment;
30 |
31 | import java.text.SimpleDateFormat;
32 | import java.util.Date;
33 |
34 | import de.spiritcroc.modular_remote.BuildConfig;
35 | import de.spiritcroc.modular_remote.R;
36 | import de.spiritcroc.modular_remote.Util;
37 |
38 | public class AboutDialog extends DialogFragment {
39 | private static final String LOG_TAG = AboutDialog.class.getSimpleName();
40 |
41 | @Override
42 | public Dialog onCreateDialog(Bundle savedInstanceState) {
43 | Activity activity = getActivity();
44 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
45 | View view = activity.getLayoutInflater().inflate(R.layout.dialog_about, null);
46 | String text;
47 | if (BuildConfig.DEBUG) {
48 | text = getString(R.string.dialog_about_app_debug_version,
49 | BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.GIT_DESCRIBE,
50 | SimpleDateFormat.getDateTimeInstance().format(
51 | new Date(BuildConfig.TIMESTAMP)));
52 | } else {
53 | text = getString(R.string.dialog_about_app_version, BuildConfig.VERSION_NAME,
54 | BuildConfig.VERSION_CODE);
55 | }
56 | ((TextView) view.findViewById(R.id.version_view)).setText(text);
57 | builder.setView(Util.scrollView(view))
58 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
59 | @Override
60 | public void onClick(DialogInterface dialog, int which) {
61 | // Only close dialog
62 | }
63 | })
64 | .setNeutralButton(R.string.dialog_greeting, new DialogInterface.OnClickListener() {
65 | @Override
66 | public void onClick(DialogInterface dialog, int which) {
67 | new GreetingDialog().show(getFragmentManager(), "GreetingDialog");
68 | }
69 | });
70 |
71 | return builder.create();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/CommandInterface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | public interface CommandInterface {
22 | void setCommand(int id, String command);
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/CustomDialogFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.content.DialogInterface;
22 |
23 | import androidx.fragment.app.DialogFragment;
24 |
25 | public abstract class CustomDialogFragment extends DialogFragment {
26 | private OnDismissListener onDismissListener;
27 |
28 | public CustomDialogFragment setOnDismissListener(OnDismissListener onDismissListener) {
29 | this.onDismissListener = onDismissListener;
30 | return this;
31 | }
32 |
33 | @Override
34 | public void onDismiss(DialogInterface dialog) {
35 | super.onDismiss(dialog);
36 | if (onDismissListener != null) {
37 | onDismissListener.onDismiss();
38 | }
39 | }
40 |
41 | public interface OnDismissListener {
42 | void onDismiss();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/GreetingDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.content.SharedPreferences;
25 | import android.os.Bundle;
26 | import android.preference.PreferenceManager;
27 | import android.text.method.LinkMovementMethod;
28 | import android.util.TypedValue;
29 | import android.widget.TextView;
30 |
31 | import androidx.appcompat.app.AlertDialog;
32 | import androidx.fragment.app.DialogFragment;
33 |
34 | import de.spiritcroc.modular_remote.Preferences;
35 | import de.spiritcroc.modular_remote.R;
36 | import de.spiritcroc.modular_remote.Util;
37 |
38 | public class GreetingDialog extends DialogFragment {
39 |
40 | // Increment if content significantly changes and should be seen again
41 | public static int VERSION = 1;
42 |
43 | @Override
44 | public Dialog onCreateDialog(Bundle savedInstanceState) {
45 | Activity activity = getActivity();
46 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
47 | TextView view = new TextView(getActivity());
48 | int padding = getResources().getDimensionPixelSize(R.dimen.dialog_content_padding);
49 | view.setPadding(padding, padding, padding, padding);
50 | view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
51 | view.setText(R.string.dialog_greeting_message);
52 | view.setMovementMethod(LinkMovementMethod.getInstance());
53 | builder.setTitle(R.string.dialog_greeting)
54 | .setView(Util.scrollView(view))
55 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
56 | @Override
57 | public void onClick(DialogInterface dialog, int which) {
58 | SharedPreferences preferences =
59 | PreferenceManager.getDefaultSharedPreferences(getActivity());
60 | preferences.edit().putInt(Preferences.SEEN_GREETING_VERSION, VERSION)
61 | .apply();
62 | if (SetupGridSizeDialog.shouldShow(preferences)) {
63 | new SetupGridSizeDialog()
64 | .show(getFragmentManager(), "SetupGridSizeDialog");
65 | }
66 | }
67 | });
68 |
69 | return builder.create();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/HideSubmenuItemsDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 |
26 | import androidx.appcompat.app.AlertDialog;
27 | import androidx.fragment.app.DialogFragment;
28 |
29 | import de.spiritcroc.modular_remote.R;
30 | import de.spiritcroc.modular_remote.TcpConnectionManager;
31 | import de.spiritcroc.modular_remote.TcpInformation;
32 |
33 | public class HideSubmenuItemsDialog extends DialogFragment {
34 | private TcpConnectionManager.TcpConnection connection;
35 | private int submenu;
36 | private String submenuName;
37 |
38 | public HideSubmenuItemsDialog setValues(TcpConnectionManager.TcpConnection connection,
39 | int submenu, String submenuName) {
40 | this.connection = connection;
41 | this.submenu = submenu;
42 | this.submenuName = submenuName;
43 | return this;
44 | }
45 |
46 | @Override
47 | public Dialog onCreateDialog(Bundle savedInstanceState) {
48 | final Activity activity = getActivity();
49 | final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
50 |
51 | final TcpConnectionManager.TcpConnection.CustomizedMenu customizedMenu =
52 | connection.requireCustomizedMenu(submenu, activity);
53 | final boolean[] selection = customizedMenu.getHidden();
54 |
55 | return builder.setTitle(getString(R.string.dialog_hide) + submenuName)
56 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
57 | @Override
58 | public void onClick(DialogInterface dialog, int which) {
59 | // Only close dialog
60 | }
61 | })
62 | .setNeutralButton(R.string.dialog_reset, new DialogInterface.OnClickListener() {
63 | @Override
64 | public void onClick(DialogInterface dialog, int which) {
65 | customizedMenu.resetHidden();
66 | connection.updateListeners(new TcpInformation(
67 | TcpInformation.InformationType.UPDATE_MENU,
68 | customizedMenu.getMenuValue()));
69 |
70 | }
71 | })
72 | .setPositiveButton(R.string.dialog_hide_selected,
73 | new DialogInterface.OnClickListener() {
74 | @Override
75 | public void onClick(DialogInterface dialog, int which) {
76 | customizedMenu.hidden = selection;
77 | connection.updateListeners(new TcpInformation(
78 | TcpInformation.InformationType.UPDATE_MENU,
79 | customizedMenu.getMenuValue()));
80 | }
81 | })
82 | .setMultiChoiceItems(customizedMenu.names, selection,
83 | new DialogInterface.OnMultiChoiceClickListener() {
84 | @Override
85 | public void onClick(DialogInterface dialog, int which,
86 | boolean isChecked) {
87 | selection[which] = isChecked;
88 | }
89 | }).create();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/OverlapWarningDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.util.Log;
26 |
27 | import androidx.appcompat.app.AlertDialog;
28 | import androidx.fragment.app.DialogFragment;
29 |
30 | import de.spiritcroc.modular_remote.MainActivity;
31 | import de.spiritcroc.modular_remote.R;
32 |
33 | public class OverlapWarningDialog extends DialogFragment {
34 | private static String LOG_TAG = OverlapWarningDialog.class.getSimpleName();
35 |
36 | private MainActivity callback;
37 |
38 | @Override
39 | public Dialog onCreateDialog(Bundle savedInstanceState) {
40 | Activity activity = getActivity();
41 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
42 | builder.setTitle(R.string.dialog_warning)
43 | .setMessage(R.string.dialog_overlapping_fragments_warning)
44 | .setPositiveButton(R.string.dialog_change, new DialogInterface.OnClickListener() {
45 | @Override
46 | public void onClick(DialogInterface dialog, int which) {
47 | if (callback == null) {
48 | Log.e(LOG_TAG, "callback == null");
49 | } else {
50 | callback.enterEditMode();
51 | }
52 | }
53 | })
54 | .setNegativeButton(R.string.dialog_ignore, new DialogInterface.OnClickListener() {
55 | @Override
56 | public void onClick(DialogInterface dialog, int which) {
57 | if (callback == null) {
58 | Log.e(LOG_TAG, "callback == null");
59 | } else {
60 | callback.exitEditMode();
61 | }
62 | }
63 | });
64 |
65 | return builder.create();
66 | }
67 |
68 | public OverlapWarningDialog setCallback(MainActivity callback) {
69 | this.callback = callback;
70 | return this;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/OverwriteTypeDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 |
26 | import androidx.appcompat.app.AlertDialog;
27 | import androidx.fragment.app.DialogFragment;
28 |
29 | import de.spiritcroc.modular_remote.R;
30 | import de.spiritcroc.modular_remote.ReceiverIpSelectorUser;
31 | import de.spiritcroc.modular_remote.TcpConnectionManager;
32 |
33 | public class OverwriteTypeDialog extends DialogFragment {
34 | private TcpConnectionManager.TcpConnection tcpConnection;
35 | private TcpConnectionManager.ReceiverType receiverType;
36 | private ReceiverIpSelectorUser waiter;
37 |
38 | @Override
39 | public Dialog onCreateDialog(Bundle savedInstanceState){
40 | final Activity activity = getActivity();
41 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
42 |
43 | String message = getString(R.string.dialog_overwrite_receiver_type_message,
44 | TcpConnectionManager.getReceiverTypeDisplayString(
45 | getResources(), tcpConnection.getType()),
46 | TcpConnectionManager.getReceiverTypeDisplayString(getResources(), receiverType));
47 |
48 | return builder.setTitle(R.string.dialog_overwrite_receiver_type)
49 | .setMessage(message)
50 | .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() {
51 | @Override
52 | public void onClick(DialogInterface dialog, int which) {
53 | //only dismiss this dialog
54 | }
55 | }).setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() {
56 | @Override
57 | public void onClick(DialogInterface dialog, int which) {
58 | tcpConnection.setType(receiverType);
59 | waiter.resumeDismiss();
60 | }
61 | }).create();
62 | }
63 |
64 | public OverwriteTypeDialog setValues(TcpConnectionManager.TcpConnection tcpConnection,
65 | TcpConnectionManager.ReceiverType receiverType,
66 | ReceiverIpSelectorUser waiter) {
67 | this.tcpConnection = tcpConnection;
68 | this.receiverType = receiverType;
69 | this.waiter = waiter;
70 | return this;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/RemoveConnectionDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.util.Log;
26 |
27 | import androidx.appcompat.app.AlertDialog;
28 | import androidx.fragment.app.DialogFragment;
29 |
30 | import de.spiritcroc.modular_remote.R;
31 | import de.spiritcroc.modular_remote.TcpConnectionManager;
32 |
33 | public class RemoveConnectionDialog extends DialogFragment {
34 | private final static String LOG_TAG = RemoveConnectionDialog.class.getSimpleName();
35 |
36 | private TcpConnectionManager.TcpConnection connection;
37 |
38 | public RemoveConnectionDialog setConnection(TcpConnectionManager.TcpConnection connection) {
39 | this.connection = connection;
40 | return this;
41 | }
42 |
43 | @Override
44 | public Dialog onCreateDialog(Bundle savedInstanceState) {
45 | final Activity activity = getActivity();
46 | AlertDialog.Builder builder = new AlertDialog.Builder(activity);
47 |
48 | String ip;
49 | if (connection == null) {
50 | Log.e(LOG_TAG, "connection == null");
51 | dismiss();
52 | ip = "";
53 | } else {
54 | ip = connection.getIp();
55 | }
56 |
57 | return builder.setTitle(R.string.dialog_remove_connection)
58 | .setMessage(getString(R.string.dialog_remove_connection_message, ip))
59 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
60 | @Override
61 | public void onClick(DialogInterface dialog, int which) {
62 | // Only dismiss
63 | }
64 | }).setPositiveButton(R.string.dialog_remove, new DialogInterface.OnClickListener() {
65 | @Override
66 | public void onClick(DialogInterface dialog, int which) {
67 | if (connection != null) {
68 | TcpConnectionManager.getInstance(getActivity().getApplicationContext())
69 | .removeConnection(connection);
70 | }
71 | }
72 | }).create();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/RemoveContainerDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.util.Log;
26 |
27 | import androidx.appcompat.app.AlertDialog;
28 | import androidx.fragment.app.DialogFragment;
29 |
30 | import de.spiritcroc.modular_remote.MainActivity;
31 | import de.spiritcroc.modular_remote.R;
32 | import de.spiritcroc.modular_remote.modules.ModuleFragment;
33 | import de.spiritcroc.modular_remote.modules.PageContainerFragment;
34 |
35 | public class RemoveContainerDialog extends DialogFragment {
36 | private static final String LOG_TAG = RemoveContainerDialog.class.getSimpleName();
37 |
38 | private ModuleFragment fragment;
39 |
40 | public RemoveContainerDialog setFragment(ModuleFragment fragment) {
41 | this.fragment = fragment;
42 | return this;
43 | }
44 |
45 | @Override
46 | public Dialog onCreateDialog(Bundle savedInstanceState) {
47 | return new AlertDialog.Builder(getActivity())
48 | .setMessage(getString(R.string.dialog_remove_container, fragment.getReadableName()))
49 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
50 | @Override
51 | public void onClick(DialogInterface dialog, int which) {
52 | // Only close dialog
53 | }
54 | })
55 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
56 | @Override
57 | public void onClick(DialogInterface dialog, int which) {
58 | if (fragment instanceof PageContainerFragment) {
59 | Activity activity = getActivity();
60 | if (activity instanceof MainActivity) {
61 | ((MainActivity) activity)
62 | .removePage((PageContainerFragment) fragment, true);
63 | } else {
64 | Log.e(LOG_TAG, "!(getActivity() instanceof MainActivity)");
65 | }
66 | } else {
67 | fragment.getParent().removeFragment(fragment, true);
68 | }
69 | }
70 | })
71 | .create();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/SelectConnectionDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 |
26 | import androidx.appcompat.app.AlertDialog;
27 | import androidx.fragment.app.DialogFragment;
28 |
29 | import de.spiritcroc.modular_remote.R;
30 | import de.spiritcroc.modular_remote.TcpConnectionManager;
31 |
32 | public class SelectConnectionDialog extends DialogFragment {
33 | private int selection = 0;
34 |
35 | @Override
36 | public Dialog onCreateDialog(Bundle savedInstanceState) {
37 | final Activity activity = getActivity();
38 | final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
39 |
40 | final String[] items = TcpConnectionManager.getInstance(getActivity()
41 | .getApplicationContext()).getConnectionSuggestions();
42 |
43 | return builder.setTitle(R.string.dialog_select_connection)
44 | .setSingleChoiceItems(items, selection, new DialogInterface.OnClickListener() {
45 | @Override
46 | public void onClick(DialogInterface dialog, int which) {
47 | selection = which;
48 | }
49 | })
50 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
51 | @Override
52 | public void onClick(DialogInterface dialog, int which) {
53 | // Only close dialog
54 | }
55 | })
56 | .setPositiveButton(R.string.dialog_edit, new DialogInterface.OnClickListener() {
57 | @Override
58 | public void onClick(DialogInterface dialog, int which) {
59 | new EditConnectionDialog().setConnection(TcpConnectionManager
60 | .getInstance(getActivity().getApplicationContext())
61 | .getTcpConnection(items[selection]))
62 | .show(getFragmentManager(), "EditConnectionDialog");
63 | }
64 | })
65 | .setNeutralButton(R.string.dialog_remove, new DialogInterface.OnClickListener() {
66 | @Override
67 | public void onClick(DialogInterface dialog, int which) {
68 | new RemoveConnectionDialog().setConnection(TcpConnectionManager
69 | .getInstance(getActivity().getApplicationContext())
70 | .getTcpConnection(items[selection]))
71 | .show(getFragmentManager(), "RemoveConnectionDialog");
72 | }
73 | })
74 | .create();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/SelectEditSubmenuDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 |
26 | import androidx.appcompat.app.AlertDialog;
27 | import androidx.fragment.app.DialogFragment;
28 |
29 | import java.util.ArrayList;
30 |
31 | import de.spiritcroc.modular_remote.R;
32 | import de.spiritcroc.modular_remote.TcpConnectionManager;
33 |
34 | public class SelectEditSubmenuDialog extends DialogFragment {
35 | private TcpConnectionManager.TcpConnection connection;
36 | private int selection = 0;
37 |
38 | @Override
39 | public Dialog onCreateDialog(Bundle savedInstanceState) {
40 | final Activity activity = getActivity();
41 | final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
42 |
43 | final String[] allNames = TcpConnectionManager.getCustomizableSubmenuNames(getResources(),
44 | connection.getType());
45 | final int[] allSubmenus =
46 | TcpConnectionManager.getCustomizableSubmenus(getResources(), connection.getType()),
47 | allValues = TcpConnectionManager.getCustomizableSubmenuValues(getResources(),
48 | connection.getType());
49 | final ArrayList names = new ArrayList<>();
50 | final ArrayList submenus = new ArrayList<>();
51 | for (int i = 0; i < allValues.length; i++) {
52 | if ((allValues[i] & TcpConnectionManager.CUSTOMIZABLE_SUBMENU_FLAG_HIDE_ITEMS) ==
53 | TcpConnectionManager.CUSTOMIZABLE_SUBMENU_FLAG_HIDE_ITEMS) {
54 | names.add(allNames[i]);
55 | submenus.add(allSubmenus[i]);
56 | }
57 | }
58 |
59 |
60 | return builder.setTitle(R.string.dialog_select_submenu)
61 | .setSingleChoiceItems(names.toArray(new String[names.size()]), selection,
62 | new DialogInterface.OnClickListener() {
63 | @Override
64 | public void onClick(DialogInterface dialog, int which) {
65 | selection = which;
66 | }
67 | })
68 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
69 | @Override
70 | public void onClick(DialogInterface dialog, int which) {
71 | //only close dialog
72 | }
73 | })
74 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
75 | @Override
76 | public void onClick(DialogInterface dialog, int which) {
77 | new HideSubmenuItemsDialog().setValues(connection, submenus.get(selection),
78 | names.get(selection))
79 | .show(getFragmentManager(), "HideSubmenuItemsDialog");
80 | }
81 | })
82 | .create();
83 | }
84 |
85 | public SelectEditSubmenuDialog setConnection(TcpConnectionManager.TcpConnection connection) {
86 | this.connection = connection;
87 | return this;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/SortFragmentsDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.text.Spannable;
26 | import android.text.SpannableString;
27 | import android.view.View;
28 | import android.widget.ArrayAdapter;
29 |
30 | import androidx.appcompat.app.AlertDialog;
31 |
32 | import java.util.ArrayList;
33 |
34 | import de.spiritcroc.modular_remote.R;
35 | import de.spiritcroc.modular_remote.dslv.DragSortListView;
36 | import de.spiritcroc.modular_remote.modules.Container;
37 | import de.spiritcroc.modular_remote.modules.ModuleFragment;
38 |
39 | public class SortFragmentsDialog extends CustomDialogFragment {
40 |
41 | private Container container;
42 | private ModuleFragment[] initFragments;
43 | private ArrayList sortFragments = new ArrayList<>();
44 | private ArrayList sortFragmentNames = new ArrayList<>();
45 | private ArrayAdapter arrayAdapter;
46 |
47 | @Override
48 | public Dialog onCreateDialog(Bundle savedInstanceState){
49 | final Activity activity = getActivity();
50 | final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
51 |
52 | View view = activity.getLayoutInflater().inflate(R.layout.dialog_sort, null);
53 |
54 | DragSortListView dslv = (DragSortListView) view.findViewById(R.id.drag_sort_list);
55 |
56 | initFragments = container.getFragments();
57 | for (ModuleFragment fragment: initFragments) {
58 | sortFragments.add(fragment);
59 | sortFragmentNames.add(fragment instanceof Container ?
60 | ((Container) fragment).getContentReadableName(null) :
61 | new SpannableString(fragment.getReadableName()));
62 | }
63 |
64 | arrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1,
65 | sortFragmentNames);
66 | dslv.setAdapter(arrayAdapter);
67 | dslv.setDropListener(new DragSortListView.DropListener() {
68 | @Override
69 | public void drop(int from, int to) {
70 | sortFragments.add(to, sortFragments.remove(from));
71 | sortFragmentNames.add(to, sortFragmentNames.remove(from));
72 | arrayAdapter.notifyDataSetChanged();
73 | }
74 | });
75 |
76 | return builder.setTitle(R.string.dialog_sort_fragments)
77 | .setPositiveButton(R.string.dialog_apply, new DialogInterface.OnClickListener() {
78 | @Override
79 | public void onClick(DialogInterface dialog, int which) {
80 | // Remove
81 | for (int i = 0; i < sortFragments.size(); i++) {
82 | container.removeFragment(sortFragments.get(i), false);
83 | }
84 | // Re-add in new order
85 | for (int i = 0; i < sortFragments.size(); i++) {
86 | container.addFragment(sortFragments.get(i), true);
87 | }
88 | }
89 | })
90 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
91 | @Override
92 | public void onClick(DialogInterface dialog, int which) {
93 | // Close dialog
94 | }
95 | })
96 | .setView(view).create();
97 | }
98 |
99 | public SortFragmentsDialog setContainer(Container container) {
100 | this.container = container;
101 | return this;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dialogs/SortPagesDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.dialogs;
20 |
21 | import android.app.Activity;
22 | import android.app.Dialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.util.Log;
26 | import android.view.View;
27 | import android.widget.ArrayAdapter;
28 |
29 | import androidx.appcompat.app.AlertDialog;
30 | import androidx.fragment.app.DialogFragment;
31 |
32 | import java.util.ArrayList;
33 |
34 | import de.spiritcroc.modular_remote.MainActivity;
35 | import de.spiritcroc.modular_remote.R;
36 | import de.spiritcroc.modular_remote.dslv.DragSortListView;
37 | import de.spiritcroc.modular_remote.modules.PageContainerFragment;
38 |
39 | public class SortPagesDialog extends DialogFragment {
40 | private static final String LOG_TAG = SortPagesDialog.class.getSimpleName();
41 |
42 | private ArrayList sortPageNames = new ArrayList<>();
43 | private ArrayList sortOrder = new ArrayList<>();
44 | private ArrayAdapter arrayAdapter;
45 |
46 | @Override
47 | public Dialog onCreateDialog(Bundle savedInstanceState){
48 | final Activity activity = getActivity();
49 | final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
50 |
51 | View view = activity.getLayoutInflater().inflate(R.layout.dialog_sort, null);
52 |
53 | if (activity instanceof MainActivity) {
54 | MainActivity mainActivity = (MainActivity) activity;
55 |
56 | DragSortListView dslv = (DragSortListView) view.findViewById(R.id.drag_sort_list);
57 |
58 | PageContainerFragment[] initPages = mainActivity.getPages();
59 |
60 | for (PageContainerFragment page: initPages) {
61 | sortPageNames.add(page.getName());
62 | sortOrder.add(sortOrder.size());
63 | }
64 |
65 | arrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1,
66 | sortPageNames);
67 | dslv.setAdapter(arrayAdapter);
68 | dslv.setDropListener(new DragSortListView.DropListener() {
69 | @Override
70 | public void drop(int from, int to) {
71 | sortPageNames.add(to, sortPageNames.remove(from));
72 | sortOrder.add(to, sortOrder.remove(from));
73 | arrayAdapter.notifyDataSetChanged();
74 | }
75 | });
76 | } else {
77 | Log.e(LOG_TAG, "!(activity instanceof MainActivity)");
78 | }
79 |
80 | return builder.setTitle(R.string.dialog_sort_pages)
81 | .setPositiveButton(R.string.dialog_apply, new DialogInterface.OnClickListener() {
82 | @Override
83 | public void onClick(DialogInterface dialog, int which) {
84 | if (activity instanceof MainActivity) {
85 | ((MainActivity) activity).orderPages(sortOrder);
86 | } else {
87 | Log.e(LOG_TAG, "!(activity instanceof MainActivity)");
88 | }
89 | }
90 | })
91 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
92 | @Override
93 | public void onClick(DialogInterface dialog, int which) {
94 | // Close dialog
95 | }
96 | })
97 | .setView(view).create();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dslv/DragSortItemView.java:
--------------------------------------------------------------------------------
1 | package de.spiritcroc.modular_remote.dslv;
2 |
3 | import android.content.Context;
4 | import android.view.Gravity;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.AbsListView;
8 |
9 | /**
10 | * Lightweight ViewGroup that wraps list items obtained from user's
11 | * ListAdapter. ItemView expects a single child that has a definite
12 | * height (i.e. the child's layout height is not MATCH_PARENT).
13 | * The width of
14 | * ItemView will always match the width of its child (that is,
15 | * the width MeasureSpec given to ItemView is passed directly
16 | * to the child, and the ItemView measured width is set to the
17 | * child's measured width). The height of ItemView can be anything;
18 | * the
19 | *
20 | *
21 | * The purpose of this class is to optimize slide
22 | * shuffle animations.
23 | */
24 | public class DragSortItemView extends ViewGroup {
25 |
26 | private int mGravity = Gravity.TOP;
27 |
28 | public DragSortItemView(Context context) {
29 | super(context);
30 |
31 | // always init with standard ListView layout params
32 | setLayoutParams(new AbsListView.LayoutParams(
33 | ViewGroup.LayoutParams.FILL_PARENT,
34 | ViewGroup.LayoutParams.WRAP_CONTENT));
35 |
36 | //setClipChildren(true);
37 | }
38 |
39 | public void setGravity(int gravity) {
40 | mGravity = gravity;
41 | }
42 |
43 | public int getGravity() {
44 | return mGravity;
45 | }
46 |
47 | @Override
48 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
49 | final View child = getChildAt(0);
50 |
51 | if (child == null) {
52 | return;
53 | }
54 |
55 | if (mGravity == Gravity.TOP) {
56 | child.layout(0, 0, getMeasuredWidth(), child.getMeasuredHeight());
57 | } else {
58 | child.layout(0, getMeasuredHeight() - child.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight());
59 | }
60 | }
61 |
62 | /**
63 | *
64 | */
65 | @Override
66 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
67 |
68 | int height = MeasureSpec.getSize(heightMeasureSpec);
69 | int width = MeasureSpec.getSize(widthMeasureSpec);
70 |
71 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
72 |
73 | final View child = getChildAt(0);
74 | if (child == null) {
75 | setMeasuredDimension(0, width);
76 | return;
77 | }
78 |
79 | if (child.isLayoutRequested()) {
80 | // Always let child be as tall as it wants.
81 | measureChild(child, widthMeasureSpec,
82 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
83 | }
84 |
85 | if (heightMode == MeasureSpec.UNSPECIFIED) {
86 | ViewGroup.LayoutParams lp = getLayoutParams();
87 |
88 | if (lp.height > 0) {
89 | height = lp.height;
90 | } else {
91 | height = child.getMeasuredHeight();
92 | }
93 | }
94 |
95 | setMeasuredDimension(width, height);
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dslv/DragSortItemViewCheckable.java:
--------------------------------------------------------------------------------
1 | package de.spiritcroc.modular_remote.dslv;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.widget.Checkable;
6 |
7 | /**
8 | * Lightweight ViewGroup that wraps list items obtained from user's
9 | * ListAdapter. ItemView expects a single child that has a definite
10 | * height (i.e. the child's layout height is not MATCH_PARENT).
11 | * The width of
12 | * ItemView will always match the width of its child (that is,
13 | * the width MeasureSpec given to ItemView is passed directly
14 | * to the child, and the ItemView measured width is set to the
15 | * child's measured width). The height of ItemView can be anything;
16 | * the
17 | *
18 | *
19 | * The purpose of this class is to optimize slide
20 | * shuffle animations.
21 | */
22 | public class DragSortItemViewCheckable extends DragSortItemView implements Checkable {
23 |
24 | public DragSortItemViewCheckable(Context context) {
25 | super(context);
26 | }
27 |
28 | @Override
29 | public boolean isChecked() {
30 | View child = getChildAt(0);
31 | if (child instanceof Checkable)
32 | return ((Checkable) child).isChecked();
33 | else
34 | return false;
35 | }
36 |
37 | @Override
38 | public void setChecked(boolean checked) {
39 | View child = getChildAt(0);
40 | if (child instanceof Checkable)
41 | ((Checkable) child).setChecked(checked);
42 | }
43 |
44 | @Override
45 | public void toggle() {
46 | View child = getChildAt(0);
47 | if (child instanceof Checkable)
48 | ((Checkable) child).toggle();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/dslv/SimpleFloatViewManager.java:
--------------------------------------------------------------------------------
1 | package de.spiritcroc.modular_remote.dslv;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Point;
5 | import android.graphics.Color;
6 | import android.widget.ListView;
7 | import android.widget.ImageView;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | /**
12 | * Simple implementation of the FloatViewManager class. Uses list
13 | * items as they appear in the ListView to create the floating View.
14 | */
15 | public class SimpleFloatViewManager implements DragSortListView.FloatViewManager {
16 |
17 | private Bitmap mFloatBitmap;
18 |
19 | private ImageView mImageView;
20 |
21 | private int mFloatBGColor = Color.BLACK;
22 |
23 | private ListView mListView;
24 |
25 | public SimpleFloatViewManager(ListView lv) {
26 | mListView = lv;
27 | }
28 |
29 | public void setBackgroundColor(int color) {
30 | mFloatBGColor = color;
31 | }
32 |
33 | /**
34 | * This simple implementation creates a Bitmap copy of the
35 | * list item currently shown at ListView position
.
36 | */
37 | @Override
38 | public View onCreateFloatView(int position) {
39 | // Guaranteed that this will not be null? I think so. Nope, got
40 | // a NullPointerException once...
41 | View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition());
42 |
43 | if (v == null) {
44 | return null;
45 | }
46 |
47 | v.setPressed(false);
48 |
49 | // Create a copy of the drawing cache so that it does not get
50 | // recycled by the framework when the list tries to clean up memory
51 | //v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
52 | v.setDrawingCacheEnabled(true);
53 | mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache());
54 | v.setDrawingCacheEnabled(false);
55 |
56 | if (mImageView == null) {
57 | mImageView = new ImageView(mListView.getContext());
58 | }
59 | mImageView.setBackgroundColor(mFloatBGColor);
60 | mImageView.setPadding(0, 0, 0, 0);
61 | mImageView.setImageBitmap(mFloatBitmap);
62 | mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight()));
63 |
64 | return mImageView;
65 | }
66 |
67 | /**
68 | * This does nothing
69 | */
70 | @Override
71 | public void onDragFloatView(View floatView, Point position, Point touch) {
72 | // do nothing
73 | }
74 |
75 | /**
76 | * Removes the Bitmap from the ImageView created in
77 | * onCreateFloatView() and tells the system to recycle it.
78 | */
79 | @Override
80 | public void onDestroyFloatView(View floatView) {
81 | ((ImageView) floatView).setImageDrawable(null);
82 |
83 | mFloatBitmap.recycle();
84 | mFloatBitmap = null;
85 | }
86 |
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/java/de/spiritcroc/modular_remote/modules/Container.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 SpiritCroc
3 | * Email: spiritcroc@gmail.com
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package de.spiritcroc.modular_remote.modules;
20 |
21 | import android.text.Spannable;
22 |
23 | import androidx.annotation.Nullable;
24 |
25 | import de.spiritcroc.modular_remote.ResizeFrame;
26 |
27 | public interface Container {
28 | void addFragment(ModuleFragment fragment, boolean post);
29 |
30 | /**
31 | * @param callOnRemove
32 | * True if fragment will be completely removed, false if fragment will get added to a container
33 | * later
34 | */
35 | void removeFragment(ModuleFragment fragment, boolean callOnRemove);
36 | int getDepth();
37 | boolean scrollsX();
38 | boolean scrollsY();
39 | /**
40 | * @return
41 | * Scroll offset in x-direction
42 | */
43 | int getScrollX();
44 | /**
45 | * @return
46 | * Scroll offset in y-direction
47 | */
48 | int getScrollY();
49 |
50 | /**
51 | * If container needs some resizing because of moved content, it can be called in this method
52 | */
53 | void onContentMoved();
54 |
55 | /**
56 | * @return
57 | * Util.getAllContainers()
58 | */
59 | Container[] getAllContainers();
60 |
61 | /**
62 | * @return
63 | * Container that calls the method and all contained elements
64 | */
65 | ModuleFragment[] getAllFragments();
66 |
67 | /**
68 | * @return
69 | * Directly contained elements
70 | */
71 | ModuleFragment[] getFragments();
72 |
73 | /**
74 | * @return
75 | * Util.getContainerContentReadableName()
76 | */
77 | Spannable getContentReadableName(@Nullable String prefix);
78 |
79 | boolean isEmpty();
80 | int getFragmentCount();
81 |
82 | String getReadableName();
83 |
84 | void addResizeFrame(ResizeFrame resizeFrame);
85 | void removeResizeFrame(ResizeFrame resizeFrame);
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_container_drag_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_action_container_drag_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_container_scroll_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_action_container_scroll_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_create_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_create_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_tune_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_tune_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_resize_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/ic_widget_resize_handle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/widget_resize_frame.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/widget_resize_frame.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/widget_resize_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-hdpi/widget_resize_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_container_drag_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_action_container_drag_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_container_scroll_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_action_container_scroll_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_add_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_add_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_create_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_create_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_tune_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_tune_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_widget_resize_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/ic_widget_resize_handle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/widget_resize_frame.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/widget_resize_frame.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/widget_resize_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-mdpi/widget_resize_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_container_drag_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_action_container_drag_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_container_scroll_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_action_container_scroll_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_create_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_create_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_tune_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_tune_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_widget_resize_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/ic_widget_resize_handle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/widget_resize_frame.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/widget_resize_frame.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/widget_resize_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xhdpi/widget_resize_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_container_drag_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_action_container_drag_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_container_scroll_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_action_container_scroll_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_create_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_create_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_tune_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_tune_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_widget_resize_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/ic_widget_resize_handle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/widget_resize_frame.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/widget_resize_frame.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/widget_resize_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxhdpi/widget_resize_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_action_container_drag_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_action_container_drag_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_action_container_scroll_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_action_container_scroll_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_create_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_create_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_tune_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_tune_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_widget_resize_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/ic_widget_resize_handle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/widget_resize_frame.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/widget_resize_frame.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/widget_resize_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/drawable-xxxhdpi/widget_resize_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_monochrome.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/abcd_alert_dialog_button_bar_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
25 |
26 |
36 |
37 |
42 |
43 |
49 |
50 |
55 |
56 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/abcd_alert_dialog_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
25 |
26 |
27 |
28 |
34 |
35 |
41 |
42 |
47 |
48 |
52 |
53 |
58 |
59 |
66 |
67 |
72 |
73 |
74 |
75 |
81 |
82 |
83 |
84 |
89 |
90 |
94 |
95 |
96 |
99 |
100 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/abcd_alert_dialog_title_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
23 |
24 |
25 |
26 |
35 |
36 |
44 |
45 |
54 |
55 |
56 |
57 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
25 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_shortcut.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
24 |
29 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
31 |
37 |
43 |
48 |
53 |
54 |
55 |
61 |
66 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_command_line_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
36 |
41 |
45 |
50 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_configure_toggle.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
34 |
40 |
45 |
46 |
47 |
52 |
57 |
58 |
63 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_edit_connection.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
31 |
36 |
41 |
46 |
50 |
51 |
56 |
61 |
62 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_enter_raw_command.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_global_action.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
36 |
37 |
42 |
46 |
47 |
52 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_select_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
36 |
43 |
50 |
51 |
52 |
56 |
63 |
70 |
77 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_setup_grid_size.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
33 |
38 |
42 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_sort.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
24 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_spinner_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
36 |
41 |
45 |
50 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_toggle_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
36 |
41 |
45 |
50 |
55 |
60 |
65 |
70 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_web_view_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
35 |
39 |
44 |
50 |
51 |
55 |
60 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_command_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_display.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_horizontal_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
27 |
31 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_page_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_scroll_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
27 |
31 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_toggle.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_web_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_widget_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
28 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_fragment_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 | #CE80cbc4
23 | #9e9e9e
24 |
25 | #303030
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 | 4dp
22 |
23 | 13dp
24 |
25 | 8dp
26 | 8dp
27 | 18dp
28 | 8dp
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dslv_attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
31 |
32 |
33 |
36 |
37 |
38 |
41 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
22 |
25 |
31 |
36 |
41 |
46 |
47 |
50 |
54 |
59 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_advanced.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
14 |
19 |
24 |
29 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_global_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_more_space.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
13 |
17 |
21 |
26 |
29 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.6.4'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | android.enableJetifier=true
20 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 12 09:31:08 CEST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/icons/ic_action_container_drag_36dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
73 |
--------------------------------------------------------------------------------
/icons/ic_action_container_scroll_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
113 |
--------------------------------------------------------------------------------
/icons/ic_action_container_scroll_36dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
76 |
--------------------------------------------------------------------------------
/known_reference_sheets.md:
--------------------------------------------------------------------------------
1 | # Known reference sheets
2 |
3 | ## Tested
4 |
5 | Pioneer:
6 | http://www.pioneerelectronics.com/StaticFiles/PUSA/Files/Home%20Custom%20Install/VSX-1120-K-RS232.PDF
7 |
8 | ## Not tested
9 |
10 | Marantz:
11 | http://m.marantz.co.uk/DocumentMaster/UK/NA7004_PROTOCOL_V01.pdf
12 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/store/description_full.txt:
--------------------------------------------------------------------------------
1 | This app is a beta! This means that you should not expect a finished fully-working app, as it's still in development!
2 |
3 | The aim of this app is to provide the user a possibility to fully create their own remote out of several modules.
4 |
5 | Currently supported remotely control-able devices:
6 | - Basically any device controllable via TCP, you just have to look up the commands when you set up your remote
7 | - Advanced support for pioneer receivers (via network): Select commands & responses (not all commands & responses supported yet)
8 | - Any device that supplies a browser-based user-interface
9 | - Any device control-able with widgets supplied by an external app
10 |
11 | Available modules:
12 | - Button
13 | - Toggle button
14 | - Dropdown list
15 | - Display
16 | - Command line
17 | - WebView
18 | - Widget
19 | - Scroll containers
20 |
21 | You can also configure multiple pages to best suit your needs depending on different occasions.
22 | If your launcher supports creating shortcuts (like e.g. NovaLauncher), you can create home screen shortcuts to your pages.
23 |
24 | Modular Remote is free, and open source. Visit the project on GitHub: https://github.com/SpiritCroc/Modular-Remote
25 | Any help would be greatly appreciated!
26 | If you want to help to natively support more devices, you can find out how to do so here: https://github.com/SpiritCroc/Modular-Remote/blob/master/guide_supporting_new_devices.md
27 |
28 | Required Permissions:
29 | android.permission.INTERNET: Required to access devices via TCP
30 | android.permission.ACCESS_NETWORK_STATE: Required to automatically connect unconnected connections on network state changed
31 |
--------------------------------------------------------------------------------
/store/descritption_short.txt:
--------------------------------------------------------------------------------
1 | Create your own remote to control your devices using TCP (and more)!
2 |
--------------------------------------------------------------------------------
/store/featured-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/store/featured-image.png
--------------------------------------------------------------------------------
/store/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/store/ic_launcher.png
--------------------------------------------------------------------------------
/store/screenshots/Screenshot_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/store/screenshots/Screenshot_01.png
--------------------------------------------------------------------------------
/store/screenshots/Screenshot_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/store/screenshots/Screenshot_02.png
--------------------------------------------------------------------------------
/store/screenshots/Screenshot_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpiritCroc/Modular-Remote/6bd35369c66cdadd6699b49acf43a59d29585521/store/screenshots/Screenshot_03.png
--------------------------------------------------------------------------------